/*****************************************************************************\
 *  as_kingbase_assoc.c - functions dealing with associations.
 *****************************************************************************
 *  Copyright (C) 2004-2007 The Regents of the University of California.
 *  Copyright (C) 2008-2010 Lawrence Livermore National Security.
 *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
 *  Written by Danny Auble <da@llnl.gov>
 *
 *  This file is part of Slurm, a resource management program.
 *  For details, see <https://slurm.schedmd.com/>.
 *  Please also read the included file: DISCLAIMER.
 *
 *  Slurm is free software; you can redistribute it and/or modify it under
 *  the terms of the GNU General Public License as published by the Free
 *  Software Foundation; either version 2 of the License, or (at your option)
 *  any later version.
 *
 *  In addition, as a special exception, the copyright holders give permission
 *  to link the code of portions of this program with the OpenSSL library under
 *  certain conditions as described in each individual source file, and
 *  distribute linked combinations including the two. You must obey the GNU
 *  General Public License in all respects for all of the code used other than
 *  OpenSSL. If you modify file(s) with this exception, you may extend this
 *  exception to your version of the file(s), but you are not obligated to do
 *  so. If you do not wish to do so, delete this exception statement from your
 *  version.  If you delete this exception statement from all source files in
 *  the program, then also delete it here.
 *
 *  Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
 *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 *  details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with Slurm; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
\*****************************************************************************/

#include "as_kingbase_assoc.h"
#include "as_kingbase_usage.h"

#ifdef __METASTACK_OPT_SACCTMGR_ADD_USER
#include "as_kingbase_user.h"
#endif

static char *tmp_cluster_name = "slurmredolftrgttemp";


/* if this changes you will need to edit the corresponding enum */
char *assoc_req_inx[] = {
	"id_assoc",
	"lft",
	"rgt",
	"user",
	"acct",
	"partition",
	"shares",
	"grp_tres_mins",
	"grp_tres_run_mins",
	"grp_tres",
	"grp_jobs",
	"grp_jobs_accrue",
	"grp_submit_jobs",
	"grp_wall",
	"max_tres_mins_pj",
	"max_tres_run_mins",
	"max_tres_pj",
	"max_tres_pn",
	"max_jobs",
	"max_jobs_accrue",
	"min_prio_thresh",
	"max_submit_jobs",
	"max_wall_pj",
	"parent_acct",
	"priority",
	"def_qos_id",
	"qos",
	"delta_qos",
	"is_def",
	"deleted",
};
enum {
	ASSOC_REQ_ID,
	ASSOC_REQ_LFT,
	ASSOC_REQ_RGT,
	ASSOC_REQ_USER,
	ASSOC_REQ_ACCT,
	ASSOC_REQ_PART,
	ASSOC_REQ_FS,
	ASSOC_REQ_GTM,
	ASSOC_REQ_GTRM,
	ASSOC_REQ_GT,
	ASSOC_REQ_GJ,
	ASSOC_REQ_GJA,
	ASSOC_REQ_GSJ,
	ASSOC_REQ_GW,
	ASSOC_REQ_MTMPJ,
	ASSOC_REQ_MTRM,
	ASSOC_REQ_MTPJ,
	ASSOC_REQ_MTPN,
	ASSOC_REQ_MJ,
	ASSOC_REQ_MJA,
	ASSOC_REQ_MPT,
	ASSOC_REQ_MSJ,
	ASSOC_REQ_MWPJ,
	ASSOC_REQ_PARENT,
	ASSOC_REQ_PRIO,
	ASSOC_REQ_DEF_QOS,
	ASSOC_REQ_QOS,
	ASSOC_REQ_DELTA_QOS,
	ASSOC_REQ_DEFAULT,
	ASSOC_REQ_DELETED,
	ASSOC_REQ_COUNT
};

/*
static char *get_parent_limits_select =
	"select @id_assoc, @max_jobs, @max_jobs_accrue, @min_prio_thresh, @max_submit_jobs, "
	"@max_wall_pj, @max_tres_pj, @max_tres_pn, @max_tres_mins_pj, @max_tres_run_mins, "
	"@def_qos_id, @qos, @delta_qos, @priority;";
*/

enum {
	ASSOC2_REQ_PARENT_ID,
	ASSOC2_REQ_MJ,
	ASSOC2_REQ_MJA,
	ASSOC2_REQ_MPT,
	ASSOC2_REQ_MSJ,
	ASSOC2_REQ_MWPJ,
	ASSOC2_REQ_MTPJ,
	ASSOC2_REQ_MTPN,
	ASSOC2_REQ_MTMPJ,
	ASSOC2_REQ_MTRM,
	ASSOC2_REQ_DEF_QOS,
	ASSOC2_REQ_QOS,
	ASSOC2_REQ_DELTA_QOS,
	ASSOC2_REQ_PRIO,
};

static char *aassoc_req_inx[] = {
	"id_assoc",
	"parent_acct",
	"lft",
	"rgt",
	"deleted"
};

enum {
	AASSOC_ID,
	AASSOC_PACCT,
	AASSOC_LFT,
	AASSOC_RGT,
	AASSOC_DELETED,
	AASSOC_COUNT
};

static char *massoc_req_inx[] = {
	"id_assoc",
	"acct",
	"parent_acct",
	"user",
	"partition",
	"lft",
	"rgt",
	"qos",
	"grp_tres_mins",
	"grp_tres_run_mins",
	"grp_tres",
	"max_tres_mins_pj",
	"max_tres_run_mins",
	"max_tres_pj",
	"max_tres_pn",
};

enum {
	MASSOC_ID,
	MASSOC_ACCT,
	MASSOC_PACCT,
	MASSOC_USER,
	MASSOC_PART,
	MASSOC_LFT,
	MASSOC_RGT,
	MASSOC_QOS,
	MASSOC_GTM,
	MASSOC_GTRM,
	MASSOC_GT,
	MASSOC_MTMPJ,
	MASSOC_MTRM,
	MASSOC_MTPJ,
	MASSOC_MTPN,
	MASSOC_COUNT
};

/* if this changes you will need to edit the corresponding
 * enum below also t1 is step_table */
static char *rassoc_req_inx[] = {
	"id_assoc",
	"lft",
	"acct",
	"parent_acct",
	"`user`",
	"partition"
};

enum {
	RASSOC_ID,
	RASSOC_LFT,
	RASSOC_ACCT,
	RASSOC_PACCT,
	RASSOC_USER,
	RASSOC_PART,
	RASSOC_COUNT
};

/*字符串中字段替换函数，str为字符串，search为字符串中需要替换的字段，replace为替换后的字段*/
/*
static void _replace_substring(char *str, const char *search, const char *replace)
{
    char *pos = strstr(str, search);
    while (pos != NULL) {
        memmove(pos + strlen(replace), pos + strlen(search), strlen(pos + strlen(search)) + 1);
        strncpy(pos, replace, strlen(replace));
        pos = strstr(pos + strlen(replace), search);
    }
}
*/

static void _move_assoc_list_to_update_list(List update_list, List assoc_list)
{
	slurmdb_assoc_rec_t *assoc;

	if (!assoc_list)
		return;

	/*
	 * NOTE: You have to use slurm_list_pop here, since
	 * kingbase is exporting something of the same type as a
	 * macro, which messes everything up
	 * (my_list.h is the bad boy).
	 */
	while ((assoc = slurm_list_pop(assoc_list))) {
		/*
		 * Only free the pointer on error as success will have
		 * moved it to update_list.
		 */
		if (addto_update_list(update_list,
				      SLURMDB_MODIFY_ASSOC,
				      assoc) != SLURM_SUCCESS)
			slurmdb_destroy_assoc_rec(assoc);
	}
}

static int _assoc_sort_cluster(void *r1, void *r2)
{
	slurmdb_assoc_rec_t *rec_a = *(slurmdb_assoc_rec_t **)r1;
	slurmdb_assoc_rec_t *rec_b = *(slurmdb_assoc_rec_t **)r2;
	int diff;

	diff = xstrcmp(rec_a->cluster, rec_b->cluster);
	if (diff < 0)
		return -1;
	else if (diff > 0)
		return 1;

	return 0;
}

/* Caller responsible for freeing query being sent in as it could be
 * changed while running the function.
 */
static int _reset_default_assoc(kingbase_conn_t *kingbase_conn,
				slurmdb_assoc_rec_t *assoc,
				char **query,
				bool add_to_update)
{
	time_t now = time(NULL);
	int rc = SLURM_SUCCESS;

	xassert(query);

	if ((assoc->is_def != 1) || !assoc->cluster
	    || !assoc->acct || !assoc->user)
		return SLURM_ERROR;

	xstrfmtcat(*query, "update `%s_%s` set is_def=0, mod_time=%ld "
		   "where (`user`='%s' and acct!='%s' and is_def=1);",
		   assoc->cluster, assoc_table, (long)now,
		   assoc->user, assoc->acct);
	if (add_to_update) {
		char *sel_query = NULL;
		KCIResult *result = NULL;
		/* If moved parent all the associations will be sent
		   so no need to do this extra step.  Else, this has
		   to be done one at a time so we can send
		   the updated assocs back to the slurmctlds
		*/
		xstrfmtcat(sel_query, "select id_assoc from `%s_%s` "
			   "where (`user`='%s' and acct!='%s' and is_def=1);",
			   assoc->cluster, assoc_table,
			   assoc->user, assoc->acct);
		DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", sel_query);
		//info("[query] line %d, %s: query: %s", __LINE__, __func__, sel_query);
		result = kingbase_db_query_ret(kingbase_conn, sel_query, 1);
		if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK) {
			KCIResultDealloc(result);
			xfree(sel_query);
			rc = SLURM_ERROR;
			goto end_it;
		}
		xfree(sel_query);
		for(int i = 0; i < KCIResultGetRowCount(result); i++){
			slurmdb_assoc_rec_t *mod_assoc = xmalloc(
				sizeof(slurmdb_assoc_rec_t));
			slurmdb_init_assoc_rec(mod_assoc, 0);

			mod_assoc->cluster = xstrdup(assoc->cluster);
			mod_assoc->id = slurm_atoul(KCIResultGetColumnValue(result, i, 0));
			mod_assoc->is_def = 0;
			if (addto_update_list(kingbase_conn->update_list,
					      SLURMDB_MODIFY_ASSOC,
					      mod_assoc)
			    != SLURM_SUCCESS) {
				slurmdb_destroy_assoc_rec(mod_assoc);
				error("couldn't add to the update list");
				rc = SLURM_ERROR;
				break;
			}
		}
		KCIResultDealloc(result);
	}
end_it:
	return rc;
}

/* assoc_mgr_lock_t should be clear before coming in here. */
static int _check_coord_qos(kingbase_conn_t *kingbase_conn, char *cluster_name,
			    char *account, char *coord_name, List qos_list)
{
	bitstr_t *request_qos, *valid_qos;
	KCIResult *result = NULL;

	// 新添加的变量
	char *qos = NULL;
	char *delta_qos = NULL;
	char *my_acct_new = NULL;
	char *found_coord_curr = NULL;
	char *found_coord = NULL;
	char *my_acct = account;

   	int rc = SLURM_SUCCESS;
	assoc_mgr_lock_t locks = {NO_LOCK, NO_LOCK, READ_LOCK, NO_LOCK,
		                      NO_LOCK, NO_LOCK, NO_LOCK};

	if (!qos_list || !list_count(qos_list))
		return SLURM_SUCCESS;

	/* If there is a variable cleared here we need to make
 	   sure we get the parent's information, if any. */
	// query = xstrdup_printf(
	//     "exec get_coord_qos('%s', '%s', '%s', '%s');",
	//     assoc_table, account,
	//     cluster_name, coord_name);
	// debug4("%d(%s:%d) query\n%s",
	//        kingbase_conn->conn, THIS_FILE, __LINE__, query);
	// //info("[query] line %d, %s: query: %s", __LINE__, __func__, query);

	do {
		char *query;
		// 准备查询语句
		query = xstrdup_printf("select t1.qos, t1.delta_qos, parent_acct, t2.user from %s_%s as t1 left outer join acct_coord_table as t2 on t1.acct=t2.acct where t1.acct = '%s' and t1.user='' and (t2.user='%s' or t2.user is null);", cluster_name, assoc_table, my_acct, coord_name);
		// 获取结果集，如果出错，返回错	result = kingbase_db_query_ret(kingbase_conn, query, 1);
		result = kingbase_db_query_ret(kingbase_conn, query, 1);
		if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK)  {
	    		KCIResultDealloc(result);
			xfree(query);
			return SLURM_ERROR;
		}
		xfree(query);

		if (KCIResultGetRowCount(result) == 0 || !KCIResultGetColumnValue(result, 0, 0)) {
			KCIResultDealloc(result);
			return SLURM_ERROR;
		}
		qos = KCIResultGetColumnValue(result, 0, 0);
		if (KCIResultGetColumnValue(result, 0, 1) != NULL) {
			char *blobstring = KCIResultGetColumnValue(result, 0, 1);
			if (delta_qos == NULL) {
				delta_qos = xstrdup(blobstring);
			} else {
				char* c = xmalloc(strlen(delta_qos)+strlen(blobstring));
				sprintf(c,"%s%s",blobstring,delta_qos);
				xfree(delta_qos);
				delta_qos = xstrdup(c);
				xfree(c);
			}
			xstrsubstituteall(delta_qos, ",,", ",");
		}
		my_acct_new = KCIResultGetColumnValue(result, 0, 2);
		found_coord_curr = KCIResultGetColumnValue(result, 0, 3);

		if (found_coord_curr != NULL) {
			found_coord = found_coord_curr;
		}

		if (found_coord == NULL) {
			qos = NULL;
			xfree(delta_qos);
			delta_qos = xstrdup("");
		}
		my_acct = my_acct_new;
		KCIResultDealloc(result);

	} while (!(xstrcmp(qos, "") != 0 || xstrcmp(my_acct, "") == 0));

	char *temp = NULL;
	if (delta_qos != NULL) {
		temp = xmalloc(strlen(qos) + strlen(delta_qos) + 1);
		sprintf(temp, "%s%s", qos, delta_qos);
		xfree(delta_qos);
		xstrsubstituteall(qos, ",,", ",");
	}
    	/* First set the values of the valid ones this coordinator has
       	    access to.
    	*/

	assoc_mgr_lock(&locks);
	valid_qos = bit_alloc(g_qos_count);
	request_qos = bit_alloc(g_qos_count);
	assoc_mgr_unlock(&locks);

	set_qos_bitstr_from_string(valid_qos, temp);
	xfree(temp);

	/* Now set the ones they are requesting */
	set_qos_bitstr_from_list(request_qos, qos_list);

	/* If they are authorized their list should be in the super set */
	if (!bit_super_set(request_qos, valid_qos))
		rc = SLURM_ERROR;

	FREE_NULL_BITMAP(valid_qos);
	FREE_NULL_BITMAP(request_qos);

	return rc;
}

/* This needs to happen to make since 2.1 code doesn't have enough
 * smarts to figure out it isn't adding a default account if just
 * adding an association to the mix.
 */
static int _make_sure_users_have_default(
	kingbase_conn_t *kingbase_conn, List user_list, List cluster_list)
{
	char *query = NULL, *cluster = NULL, *user = NULL;
	ListIterator itr = NULL, clus_itr = NULL;
	int rc = SLURM_SUCCESS;
	slurmdb_assoc_rec_t *mod_assoc;

	if (slurmdbd_conf->flags & DBD_CONF_FLAG_ALLOW_NO_DEF_ACCT)
		return rc;

	if (!user_list)
		return SLURM_SUCCESS;

	clus_itr = list_iterator_create(cluster_list);
	itr = list_iterator_create(user_list);

	while ((user = list_next(itr))) {
		while ((cluster = list_next(clus_itr))) {
			KCIResult *result = NULL;
			query = xstrdup_printf(
				"select distinct is_def, acct from "
				"(select * from `%s_%s` where `user`='%s' and deleted=0 "
				"ORDER BY is_def desc, creation_time desc) "
				"LIMIT 1;",
				cluster, assoc_table, user);
			debug4("%d(%s:%d) query\n%s",
			       kingbase_conn->conn, THIS_FILE, __LINE__, query);
			//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);	   
			result = kingbase_db_query_ret(kingbase_conn, query, 0);
			if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK) {
				KCIResultDealloc(result);
				xfree(query);
				error("couldn't query the database");
				rc = SLURM_ERROR;
				break;
			}
			xfree(query);
			/* Check to see if the user is even added to
			   the cluster.
			*/
			if (!KCIResultGetRowCount(result)) {
				KCIResultDealloc(result);
				continue;
			}

			/* check if the row is default */
			char * temp = KCIResultGetColumnValue(result, 0, 0);
			if ((*temp != '\0') && temp[0] == '1') {
				/* default found, continue */
				KCIResultDealloc(result);
				continue;
			}

			/* if we made it here, there is no default */
			query = xstrdup_printf(
				"update `%s_%s` set is_def=1 where "
				"`user`='%s' and acct='%s';",
				cluster, assoc_table, user, KCIResultGetColumnValue(result, 0, 1));
			KCIResultDealloc(result);

			DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s",
			         query);
			//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);	

			fetch_flag_t *fetch_flag = NULL;
			fetch_result_t *data_rt = NULL;
			fetch_flag = set_fetch_flag(false, false, false);
			data_rt = xmalloc(sizeof(fetch_result_t));
			rc = kingbase_for_fetch(kingbase_conn, query, fetch_flag, data_rt);
			free_res_data(data_rt, fetch_flag);
			xfree(query);
			if (rc == SLURM_ERROR) {
				error("problem with update query");
				break;
			}

			/*
			 * Now we need to add this association as the default to
			 * the update_list.
			 */
			query = xstrdup_printf(
				"select id_assoc from `%s_%s` where `user`='%s' and is_def=1 and deleted=0 LIMIT 1;",
				cluster, assoc_table, user);
			DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s",
			         query);
			if (!(result = kingbase_db_query_ret(
				      kingbase_conn, query, 0))) {
				xfree(query);
				error("couldn't query the database");
				rc = SLURM_ERROR;
				break;
			}
			xfree(query);

			/* check if the row is default */

			if (!KCIResultGetColumnValue(result, 0, 0)) {
				error("User '%s' doesn't have a default like you would expect on cluster '%s'.",
				      user, cluster);
				/* default found, continue */
				KCIResultDealloc(result);
				continue;
			}

			mod_assoc = xmalloc(sizeof(*mod_assoc));
			slurmdb_init_assoc_rec(mod_assoc, 0);
			mod_assoc->cluster = xstrdup(cluster);
			mod_assoc->id = slurm_atoul(KCIResultGetColumnValue(result, 0, 0));
			mod_assoc->is_def = 1;

			KCIResultDealloc(result);

			if (addto_update_list(kingbase_conn->update_list,
					      SLURMDB_MODIFY_ASSOC,
					      mod_assoc) != SLURM_SUCCESS) {
				slurmdb_destroy_assoc_rec(mod_assoc);
				error("couldn't add to the update list");
				rc = SLURM_ERROR;
				break;
			}
		}
		if (rc != SLURM_SUCCESS)
			break;
		list_iterator_reset(clus_itr);
	}
	list_iterator_destroy(itr);
	list_iterator_destroy(clus_itr);

	return rc;
}

/* This should take care of all the lft and rgts when you move an
 * account.  This handles deleted associations also.
 */
static int _move_account(kingbase_conn_t *kingbase_conn, uint32_t *lft, uint32_t *rgt,
			 char *cluster, char *id, char *parent, time_t now)
{
	int rc = SLURM_SUCCESS;
	KCIResult *result = NULL;

	uint32_t par_left = 0;
	uint32_t diff = 0;
	uint32_t width = 0;
	char *query = xstrdup_printf(
		"SELECT lft from `%s_%s` where acct='%s' and `user`='';",
		cluster, assoc_table, parent);
	DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", query);
	//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);
	result = kingbase_db_query_ret(kingbase_conn, query, 0);
	if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK) {
		KCIResultDealloc(result);
		xfree(query);
		return SLURM_ERROR;
	}
	xfree(query);

	if (KCIResultGetRowCount(result) == 0) {
		debug4("Can't move a none existent association");
		KCIResultDealloc(result);
		return ESLURM_INVALID_PARENT_ACCOUNT;
	}
	par_left = slurm_atoul(KCIResultGetColumnValue(result, 0, 0));
	KCIResultDealloc(result);

	diff = ((par_left + 1) - *lft);

	if (diff == 0) {
		DB_DEBUG(DB_ASSOC, kingbase_conn->conn,
		         "Trying to move association to the same position? Nothing to do.");
		//info("[query] line %d, Trying to move association to the same position? Nothing to do.", __LINE__);
		return ESLURM_SAME_PARENT_ACCOUNT;
	}

	width = (*rgt - *lft + 1);

	/* every thing below needs to be a %d not a %u because we are
	   looking for -1 */
	xstrfmtcat(query,
		   "update `%s_%s` set mod_time=%ld, deleted = deleted + 2, "
		   "lft = lft + %d, rgt = rgt + %d "
		   "WHERE lft BETWEEN %d AND %d;",
		   cluster, assoc_table, now, diff, diff, *lft, *rgt);

	xstrfmtcat(query,
		   "UPDATE `%s_%s` SET mod_time=%ld, rgt = rgt + %d WHERE "
		   "rgt > %d and deleted < 2;"
		   "UPDATE `%s_%s` SET mod_time=%ld, lft = lft + %d WHERE "
		   "lft > %d and deleted < 2;",
		   cluster, assoc_table, now, width,
		   par_left,
		   cluster, assoc_table, now, width,
		   par_left);

	xstrfmtcat(query,
		   "UPDATE `%s_%s` SET mod_time=%ld, rgt = rgt - %d WHERE "
		   "(%d < 0 and rgt > %d and deleted < 2) "
		   "or (%d > 0 and rgt > %d);"
		   "UPDATE `%s_%s` SET mod_time=%ld, lft = lft - %d WHERE "
		   "(%d < 0 and lft > %d and deleted < 2) "
		   "or (%d > 0 and lft > %d);",
		   cluster, assoc_table, now, width,
		   diff, *rgt,
		   diff, *lft,
		   cluster, assoc_table, now, width,
		   diff, *rgt,
		   diff, *lft);

	xstrfmtcat(query,
		   "update `%s_%s` set mod_time=%ld, "
		   "deleted = deleted - 2 WHERE deleted > 1;",
		   cluster, assoc_table, now);
	xstrfmtcat(query,
		   "update `%s_%s` set mod_time=%ld, "
		   "parent_acct='%s' where id_assoc = %s;",
		   cluster, assoc_table, now, parent, id);
	/* get the new lft and rgt if changed */
	xstrfmtcat(query,
		   "select lft, rgt from `%s_%s` where id_assoc = %s",
		   cluster, assoc_table, id);
	DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", query);
	//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);
	result = kingbase_db_query_ret(kingbase_conn, query, 1);
	if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK) {
		KCIResultDealloc(result);
		xfree(query);
		return SLURM_ERROR;
	}
	xfree(query);

	if (KCIResultGetRowCount(result) > 0) {
		debug4("lft and rgt were %u %u and now is %s %s",
		       *lft, *rgt, KCIResultGetColumnValue(result, 0, 0), KCIResultGetColumnValue(result, 0, 1));
		*lft = slurm_atoul(KCIResultGetColumnValue(result, 0, 0));
		*rgt = slurm_atoul(KCIResultGetColumnValue(result, 0, 1));
	}
	KCIResultDealloc(result);

	return rc;
}


/* This code will move an account from one parent to another.  This
 * should work either way in the tree.  (i.e. move child to be parent
 * of current parent, and parent to be child of child.)
 */
static int _move_parent(kingbase_conn_t *kingbase_conn, uid_t uid,
			uint32_t *lft, uint32_t *rgt,
			char *cluster,
			char *id, char *old_parent, char *new_parent,
			time_t now)
{
	KCIResult *result = NULL;

	char *query = NULL;
	int rc = SLURM_SUCCESS;

	/* first we need to see if we are going to make a child of this
	 * account the new parent.  If so we need to move that child to this
	 * accounts parent and then do the move.
	 */
	query = xstrdup_printf(
		"select id_assoc, lft, rgt from `%s_%s` "
		"where lft between %d and %d "
		"and acct='%s' and `user`='' order by lft;",
		cluster, assoc_table, *lft, *rgt,
		new_parent);
	DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", query);
	//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);
	result = kingbase_db_query_ret(kingbase_conn, query, 0);
	if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK) {
		KCIResultDealloc(result);
		xfree(query);
		return SLURM_ERROR;
	}
	xfree(query);

	if (KCIResultGetRowCount(result) > 0) {
		uint32_t child_lft = slurm_atoul(KCIResultGetColumnValue(result, 0, 1)),
			child_rgt = slurm_atoul(KCIResultGetColumnValue(result, 0, 2));

		debug4("%s(%s) %s,%s is a child of %s",
		       new_parent, KCIResultGetColumnValue(result, 0, 0), KCIResultGetColumnValue(result, 0, 1), KCIResultGetColumnValue(result, 0, 2), id);
		rc = _move_account(kingbase_conn, &child_lft, &child_rgt,
				   cluster, KCIResultGetColumnValue(result, 0, 0), old_parent, now);
	}

	KCIResultDealloc(result);

	if (rc != SLURM_SUCCESS)
		return rc;

	/* now move the one we wanted to move in the first place
	 * We need to get the new lft and rgts though since they may
	 * have changed.
	 */
	query = xstrdup_printf(
		"select lft, rgt from `%s_%s` where id_assoc=%s;",
		cluster, assoc_table, id);
	DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", query);
	//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);
	result = kingbase_db_query_ret(kingbase_conn, query, 0);
	if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK) {
		KCIResultDealloc(result);
		xfree(query);
		return SLURM_ERROR;
	}
	xfree(query);

	if (KCIResultGetRowCount(result) > 0) {
		*lft = slurm_atoul(KCIResultGetColumnValue(result, 0, 0));
		*rgt = slurm_atoul(KCIResultGetColumnValue(result, 0, 1));
		rc = _move_account(kingbase_conn, lft, rgt,
				   cluster, id, new_parent, now);
	} else {
		error("can't find parent? we were able to a second ago.");
		rc = SLURM_ERROR;
	}
	KCIResultDealloc(result);

	return rc;
}

static uint32_t _get_parent_id(
	kingbase_conn_t *kingbase_conn, char *parent, char *cluster)
{
	uint32_t parent_id = 0;
	KCIResult *result = NULL;

	char *query = NULL;

	xassert(parent);
	xassert(cluster);

	query = xstrdup_printf("select id_assoc from `%s_%s` where `user`='' "
			       "and deleted = 0 and acct='%s';",
			       cluster, assoc_table, parent);
	debug4("%d(%s:%d) query\n%s",
	       kingbase_conn->conn, THIS_FILE, __LINE__, query);
	//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);
	result = kingbase_db_query_ret(kingbase_conn, query, 1);
	if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK) {
		KCIResultDealloc(result);
		xfree(query);
		return 0;
	}
	xfree(query);

	if (KCIResultGetRowCount(result) > 0) {
		char *temp = KCIResultGetColumnValue(result, 0, 0);
		if (*temp != '\0')
			parent_id = slurm_atoul(temp);
	} else
		error("no association for parent %s on cluster %s",
		      parent, cluster);
	KCIResultDealloc(result);

	return parent_id;
}

static int _set_assoc_lft_rgt(
	kingbase_conn_t *kingbase_conn, slurmdb_assoc_rec_t *assoc)
{
	KCIResult *result = NULL;

	char *query = NULL;
	int rc = SLURM_ERROR;

	xassert(assoc->cluster);
	xassert(assoc->id);

	query = xstrdup_printf("select lft, rgt from `%s_%s` "
			       "where id_assoc=%u;",
			       assoc->cluster, assoc_table, assoc->id);
	debug4("%d(%s:%d) query\n%s",
	       kingbase_conn->conn, THIS_FILE, __LINE__, query);
	//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);
	result = kingbase_db_query_ret(kingbase_conn, query, 1);
	if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK) {
		KCIResultDealloc(result);
		xfree(query);
		return 0;
	}
	xfree(query);

	if (KCIResultGetRowCount(result) > 0) {
		char *temp = KCIResultGetColumnValue(result, 0, 0);
		if (*temp != '\0')
			assoc->lft = slurm_atoul(temp);
		temp = KCIResultGetColumnValue(result, 0, 1);
		if (*temp != '\0')
			assoc->rgt = slurm_atoul(temp);
		rc = SLURM_SUCCESS;
	} else
		error("no association (%u)", assoc->id);
	KCIResultDealloc(result);

	return rc;
}

static int _get_parend(KCIResult *result, char *parent, char* query,char *cluster,char *assoc_table, kingbase_conn_t *kingbase_conn,char **with_assoc_sql, bool flag)
{
	    char *tmp_str = NULL;
		tmp_str = xstrdup(parent);
		char *comma = ",";
		int tmp_count = 0;
		bool delta_qos_flag = false;
		if (!flag) {
			do {
				query = xstrdup_printf("select id_assoc, max_jobs, max_jobs_accrue, min_prio_thresh, max_submit_jobs, "
				"max_wall_pj, max_tres_pj, max_tres_pn, max_tres_mins_pj, max_tres_run_mins,  "
				"def_qos_id, qos, delta_qos, priority, parent_acct "  
				" from %s_%s where acct = '%s'  and `user`=''", cluster, assoc_table, tmp_str);
				debug4("%d(%s:%d) query\n%s",kingbase_conn->conn, THIS_FILE, __LINE__, query);
				result = kingbase_db_query_ret(kingbase_conn, query, 1);
				if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK) {
					KCIResultDealloc(result);
					xfree(query);
					return SLURM_ERROR;
				}
				
				xfree(query);
				if(tmp_str)
					xfree(tmp_str);

				unsigned char *blobVal = NULL;
				if (KCIResultGetRowCount(result) > 0) {
					for(int i= 0 ;i < 14; i++ ) {
						if(i == 12 && ((with_assoc_sql[11] == NULL || (strlen(with_assoc_sql[11])== 0)||delta_qos_flag))) {
							delta_qos_flag = false;
							//char * qos_tmp =xstrdup(KCIResultGetColumnValue(result, 0, i)); 
							xstrcat(with_assoc_sql[i], KCIResultGetColumnValue(result, 0, i)); 
							xstrsubstituteall(with_assoc_sql[i], ",,",",");
						}else if(i==6 || i==7 || i==8 || i==9){
							if((with_assoc_sql[i] != NULL) && strlen(with_assoc_sql[i]) && KCIResultGetColumnValue(result, 0, i) != NULL && strlen(KCIResultGetColumnValue(result, 0, i)) != 0 ){
								xstrcat(with_assoc_sql[i], comma);
							}
							xstrcat(with_assoc_sql[i], KCIResultGetColumnValue(result, 0, i));
						} else if(i == 11) {
						
							const char *blobstring = KCIResultGetColumnValue(result, 0, i);
							size_t bufLen  = KCIResultGetColumnValueLength(result, 0, i);
							if(bufLen > 0)
								blobVal = (unsigned char*) malloc(bufLen);
							blobVal = KCIUnescapeBytea((const unsigned char *)blobstring, &bufLen); // 金仓获取blob类型数据需要经过这一步处理，否则会读到异常值
							if((with_assoc_sql[i] == NULL || (strlen(with_assoc_sql[i]) == 0)) && strlen((char*)blobVal) != 0){
								with_assoc_sql[i] = xstrdup((char*)blobstring);
								delta_qos_flag = true;
							}
							if(blobVal)
								free(blobVal);
						} else{
							char *tmp1 = NULL;
							char *tmp2 = NULL;
							tmp1 = with_assoc_sql[i];
							tmp2 = KCIResultGetColumnValue(result, 0, i);
							if((tmp1 == NULL || (strlen(tmp1) == 0)) && (strlen(tmp2) == 0 || tmp2!=NULL)){
								with_assoc_sql[i] = xmalloc(strlen(KCIResultGetColumnValue(result, 0, i)) + 1);  // 分配足够的内存空间
								strcpy(with_assoc_sql[i], KCIResultGetColumnValue(result, 0, i));
							}
						}
					}
					if(strlen(KCIResultGetColumnValue(result, 0, 14)) > 0)
						tmp_str = xstrdup(KCIResultGetColumnValue(result, 0, 14));
				} 
				tmp_count++;
				KCIResultDealloc(result);
			} while ((tmp_str != NULL));
		} else {
			query = xstrdup_printf("select id_assoc, max_jobs, max_jobs_accrue, min_prio_thresh, max_submit_jobs, "
			"max_wall_pj, max_tres_pj, max_tres_pn, max_tres_mins_pj, max_tres_run_mins,  "
			"def_qos_id, qos, delta_qos, priority, parent_acct "  
			" from %s_%s where acct = '%s'  and `user`=''", cluster, assoc_table, tmp_str);
			debug4("%d(%s:%d) query\n%s",kingbase_conn->conn, THIS_FILE, __LINE__, query);
			result = kingbase_db_query_ret(kingbase_conn, query, 1);
			if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK) {
				KCIResultDealloc(result);
				xfree(query);
				return SLURM_ERROR;
			}
			xfree(query);
			if ((KCIResultGetRowCount(result) == 0)) {
				KCIResultDealloc(result);
				return SLURM_ERROR;
			}
			for(int i= 0 ;i < 14; i++ ) {
				if(i == 1 || i==4 || i ==5 ||i == 10|| i==11||i ==12 || i ==13) {
					continue;
				} else
					xstrcat(with_assoc_sql[i], KCIResultGetColumnValue(result, 0, i));
			}
			KCIResultDealloc(result);

		}
		return tmp_count;
}


static int _set_assoc_limits_for_add(
	kingbase_conn_t *kingbase_conn, slurmdb_assoc_rec_t *assoc)
{
	KCIResult *result = NULL;
    char *with_assoc_sql[14] = { NULL};
	char *query = NULL;
	char *parent = NULL;
	char *qos_delta = NULL;
	uint32_t tres_str_flags = TRES_STR_FLAG_REMOVE;

	xassert(assoc);

	if (assoc->parent_acct)
		parent = assoc->parent_acct;
	else if (assoc->user)
		parent = assoc->acct;
	else
		return SLURM_SUCCESS;
    
	/*
	query = xstrdup_printf("exec get_parent_limits('%s', "
			       "'%s', '%s', %u); %s",
			       assoc_table, parent, assoc->cluster, 0,
			       get_parent_limits_select);
	debug4("%d(%s:%d) query\n%s",
	       kingbase_conn->conn, THIS_FILE, __LINE__, query);
	//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);	 
	result = kingbase_db_query_ret(kingbase_conn, query, 1) ; 
	if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK) {
		xfree(query);
		return SLURM_ERROR;
	}
	xfree(query);
	*/
      
    int tmp_count=_get_parend(result, parent,query, assoc->cluster ,assoc_table, kingbase_conn, with_assoc_sql,0);
	if (tmp_count <= 0)
		goto end_it;
	if ((with_assoc_sql[ASSOC2_REQ_DEF_QOS] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_DEF_QOS])) && (assoc->def_qos_id == INFINITE))
		assoc->def_qos_id = slurm_atoul(with_assoc_sql[ASSOC2_REQ_DEF_QOS]);
	else if (assoc->def_qos_id == INFINITE)
		assoc->def_qos_id = 0;

	if ((with_assoc_sql[ASSOC2_REQ_MJ] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MJ])) && (assoc->max_jobs == INFINITE))
		assoc->max_jobs = slurm_atoul(with_assoc_sql[ASSOC2_REQ_MJ]);
	if ((with_assoc_sql[ASSOC2_REQ_MJA] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MJA])) 
		&& (strlen(with_assoc_sql[ASSOC2_REQ_MJA]) != 0) && (assoc->max_jobs_accrue == INFINITE))
		assoc->max_jobs_accrue = slurm_atoul(with_assoc_sql[ASSOC2_REQ_MJA]);
	if ((with_assoc_sql[ASSOC2_REQ_MPT] != NULL) && strlen(with_assoc_sql[ASSOC2_REQ_MPT]) 
		&& (assoc->min_prio_thresh == INFINITE))
		assoc->min_prio_thresh = slurm_atoul(with_assoc_sql[ASSOC2_REQ_MPT]);
	if ((with_assoc_sql[ASSOC2_REQ_MSJ] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MSJ])) && (assoc->max_submit_jobs == INFINITE))
		assoc->max_submit_jobs = slurm_atoul(with_assoc_sql[ASSOC2_REQ_MSJ]);
	if ((with_assoc_sql[ASSOC2_REQ_MWPJ] != NULL) && strlen(with_assoc_sql[ASSOC2_REQ_MWPJ]) && (assoc->max_wall_pj == INFINITE))
		assoc->max_wall_pj = slurm_atoul(with_assoc_sql[ASSOC2_REQ_MWPJ]);
	if ((with_assoc_sql[ASSOC2_REQ_PRIO] != NULL) && strlen(with_assoc_sql[ASSOC2_REQ_PRIO]) && (assoc->priority == INFINITE))
		assoc->priority = slurm_atoul(with_assoc_sql[ASSOC2_REQ_PRIO]);	
	/* For the tres limits we just concatted the limits going up
	 * the hierarchy slurmdb_tres_list_from_string will just skip
	 * over any reoccuring limit to give us the first one per
	 * TRES.
	 */
	slurmdb_combine_tres_strings(
		&assoc->max_tres_pj, with_assoc_sql[ASSOC2_REQ_MTPJ],
		tres_str_flags);
	slurmdb_combine_tres_strings(
		&assoc->max_tres_pn,  with_assoc_sql[ASSOC2_REQ_MTPN],
		tres_str_flags);
	slurmdb_combine_tres_strings(
		&assoc->max_tres_mins_pj, with_assoc_sql[ASSOC2_REQ_MTMPJ],
		tres_str_flags);
	slurmdb_combine_tres_strings(
		&assoc->max_tres_run_mins,  with_assoc_sql[ASSOC2_REQ_MTRM],
		tres_str_flags);
	if (assoc->qos_list) {
		int set = 0;
		char *tmp_char = NULL;
		ListIterator qos_itr = list_iterator_create(assoc->qos_list);
		while ((tmp_char = list_next(qos_itr))) {
			/* we don't want to include blank names */
			if (!tmp_char[0])
				continue;

			if (!set) {
				if (tmp_char[0] != '+' && tmp_char[0] != '-')
					break;
				set = 1;
			}
			xstrfmtcat(qos_delta, ",%s", tmp_char);
		}
		list_iterator_destroy(qos_itr);

		if (tmp_char) {
			/* we have the qos here nothing from parents
			   needed */
			goto end_it;
		}
		list_flush(assoc->qos_list);
	} else
		assoc->qos_list = list_create(xfree_ptr);
	if ((with_assoc_sql[ASSOC2_REQ_QOS] !=NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_QOS])!= 0))
		slurm_addto_char_list(assoc->qos_list, with_assoc_sql[ASSOC2_REQ_QOS]+1);

	if ((with_assoc_sql[ASSOC2_REQ_DELTA_QOS]) && (strlen(with_assoc_sql[ASSOC2_REQ_DELTA_QOS])!= 0))
		slurm_addto_char_list(assoc->qos_list,
				      with_assoc_sql[ASSOC2_REQ_DELTA_QOS]+1);
	if (qos_delta) {
		slurm_addto_char_list(assoc->qos_list, qos_delta+1);
		xfree(qos_delta);
	}

end_it:
	for(int i =0 ; i < 14; i++) {
		if(with_assoc_sql[i])
			xfree(with_assoc_sql[i]);
	}
	//KCIResultDealloc(result);

	return SLURM_SUCCESS;
}

/* Used to get all the users inside a lft and rgt set.  This is just
 * to send the user all the associations that are being modified from
 * a previous change to it's parent.
 */
static int _modify_unset_users(kingbase_conn_t *kingbase_conn,
			       slurmdb_assoc_rec_t *assoc,
			       char *acct,
			       uint32_t lft, uint32_t rgt,
			       List ret_list, int moved_parent)
{
	KCIResult *result = NULL;

	char *query = NULL, *object = NULL;
	int i;
	uint32_t tres_str_flags = TRES_STR_FLAG_REMOVE | TRES_STR_FLAG_NO_NULL;

	char *assoc_inx[] = {
		"id_assoc",
		"`user`",
		"acct",
		"partition",
		"max_jobs",
		"max_jobs_accrue",
		"min_prio_thresh",
		"max_submit_jobs",
		"max_tres_pj",
		"max_tres_pn",
		"max_wall_pj",
		"max_tres_mins_pj",
		"max_tres_run_mins",
		"priority",
		"def_qos_id",
		"qos",
		"delta_qos",
		"lft",
		"rgt"
	};

	enum {
		ASSOC_ID,
		ASSOC_USER,
		ASSOC_ACCT,
		ASSOC_PART,
		ASSOC_MJ,
		ASSOC_MJA,
		ASSOC_MPT,
		ASSOC_MSJ,
		ASSOC_MTPJ,
		ASSOC_MTPN,
		ASSOC_MWPJ,
		ASSOC_MTMPJ,
		ASSOC_MTRM,
		ASSOC_PRIO,
		ASSOC_DEF_QOS,
		ASSOC_QOS,
		ASSOC_DELTA_QOS,
		ASSOC_LFT,
		ASSOC_RGT,
		ASSOC_COUNT
	};

	xassert(assoc);
	xassert(assoc->cluster);

	if (!ret_list || !acct)
		return SLURM_ERROR;

	xstrcat(object, assoc_inx[0]);
	for(i=1; i<ASSOC_COUNT; i++)
		xstrfmtcat(object, ", %s", assoc_inx[i]);

	/* We want all the sub accounts and user accounts */
	query = xstrdup_printf("select distinct %s from `%s_%s` "
			       "where deleted=0 "
			       "and lft between %d and %d and "
			       "((`user` = '' and parent_acct = '%s') or "
			       "(`user` != '' and acct = '%s')) "
			       "order by lft;",
			       object, assoc->cluster, assoc_table,
			       lft, rgt, acct, acct);
	xfree(object);
	DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", query);
	//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);
	result = kingbase_db_query_ret(kingbase_conn, query, 0);
	if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK) {
		KCIResultDealloc(result);
		xfree(query);
		return SLURM_ERROR;
	}
	xfree(query);
	for(int i = 0; i < KCIResultGetRowCount(result); i++){
		slurmdb_assoc_rec_t *mod_assoc = NULL;
		int modified = 0;
		char *tmp_char = NULL;

		mod_assoc = xmalloc(sizeof(slurmdb_assoc_rec_t));
		slurmdb_init_assoc_rec(mod_assoc, 0);
		mod_assoc->id = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_ID));
		mod_assoc->cluster = xstrdup(assoc->cluster);
		char *temp = KCIResultGetColumnValue(result, i, ASSOC_DEF_QOS);
		if (*temp == '\0' && assoc->def_qos_id != NO_VAL) {
			mod_assoc->def_qos_id = assoc->def_qos_id;
			modified = 1;
		}
		temp = KCIResultGetColumnValue(result, i, ASSOC_MJ);
		if (*temp == '\0' && assoc->max_jobs != NO_VAL) {
			mod_assoc->max_jobs = assoc->max_jobs;
			modified = 1;
		}
		temp = KCIResultGetColumnValue(result, i, ASSOC_MJA);
		if (*temp == '\0' && assoc->max_jobs_accrue != NO_VAL) {
			mod_assoc->max_jobs_accrue = assoc->max_jobs_accrue;
			modified = 1;
		}
		temp = KCIResultGetColumnValue(result, i, ASSOC_MPT);
		if (*temp == '\0' && assoc->min_prio_thresh != NO_VAL) {
			mod_assoc->min_prio_thresh = assoc->min_prio_thresh;
			modified = 1;
		}
		temp = KCIResultGetColumnValue(result, i, ASSOC_MSJ);
		if (*temp == '\0' && assoc->max_submit_jobs != NO_VAL) {
			mod_assoc->max_submit_jobs = assoc->max_submit_jobs;
			modified = 1;
		}
		temp = KCIResultGetColumnValue(result, i, ASSOC_MWPJ);
		if (*temp == '\0' && assoc->max_wall_pj != NO_VAL) {
			mod_assoc->max_wall_pj = assoc->max_wall_pj;
			modified = 1;
		}
		temp = KCIResultGetColumnValue(result, i, ASSOC_PRIO);
		if (*temp == '\0' && assoc->priority != NO_VAL) {
			mod_assoc->priority = assoc->priority;
			modified = 1;
		}

		if (assoc->max_tres_pj) {
			tmp_char = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_MTPJ));
			slurmdb_combine_tres_strings(
				&tmp_char, assoc->max_tres_pj,
				tres_str_flags);
			mod_assoc->max_tres_pj = tmp_char;
			tmp_char = NULL;
			modified = 1;
		}

		if (assoc->max_tres_pn) {
			tmp_char = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_MTPN));
			slurmdb_combine_tres_strings(
				&tmp_char, assoc->max_tres_pn,
				tres_str_flags);
			mod_assoc->max_tres_pn = tmp_char;
			tmp_char = NULL;
			modified = 1;
		}

		if (assoc->max_tres_mins_pj) {
			tmp_char = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_MTPJ));
			slurmdb_combine_tres_strings(
				&tmp_char, assoc->max_tres_mins_pj,
				tres_str_flags);
			mod_assoc->max_tres_mins_pj = tmp_char;
			tmp_char = NULL;
			modified = 1;
		}

		if (assoc->max_tres_run_mins) {
			tmp_char = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_MTRM));
			slurmdb_combine_tres_strings(
				&tmp_char, assoc->max_tres_run_mins,
				tres_str_flags);
			mod_assoc->max_tres_run_mins = tmp_char;
			tmp_char = NULL;
			modified = 1;
		}
		temp = KCIResultGetColumnValue(result, i, ASSOC_QOS);
		if (*temp == '\0' && assoc->qos_list) {
			List delta_qos_list = NULL;
			char *qos_char = NULL, *delta_char = NULL;
			ListIterator delta_itr = NULL;
			ListIterator qos_itr =
				list_iterator_create(assoc->qos_list);
			char *temp1 = KCIResultGetColumnValue(result, i, ASSOC_QOS);
			if (temp1 != NULL && *temp1 != '\0') {
				delta_qos_list = list_create(xfree_ptr);
				slurm_addto_char_list(delta_qos_list,
						      KCIResultGetColumnValue(result, i, ASSOC_DELTA_QOS)+1);
				delta_itr =
					list_iterator_create(delta_qos_list);
			}

			mod_assoc->qos_list = list_create(xfree_ptr);
			/* here we are making sure a child does not
			   have the qos added or removed before we add
			   it to the parent.
			*/
			while ((qos_char = list_next(qos_itr))) {
				if (delta_itr && qos_char[0] != '=') {
					while ((delta_char =
						list_next(delta_itr))) {

						if ((qos_char[0]
						     != delta_char[0])
						    && (!xstrcmp(qos_char+1,
								 delta_char+1)))
							break;
					}
					list_iterator_reset(delta_itr);
					if (delta_char)
						continue;
				}
				list_append(mod_assoc->qos_list,
					    xstrdup(qos_char));
			}
			list_iterator_destroy(qos_itr);
			if (delta_itr)
				list_iterator_destroy(delta_itr);
			FREE_NULL_LIST(delta_qos_list);
			if (list_count(mod_assoc->qos_list)
			    || !list_count(assoc->qos_list))
				modified = 1;
			else {
				FREE_NULL_LIST(mod_assoc->qos_list);
				mod_assoc->qos_list = NULL;
			}
		}

		/* We only want to add those that are modified here */
		if (modified) {
			/* Since we aren't really changing this non
			 * user association we don't want to send it.
			 */
			char *temp = KCIResultGetColumnValue(result, i, ASSOC_USER);
			if (*temp == '\0') {
				/* This is a sub account so run it
				 * through as if it is a parent.
				 */
				_modify_unset_users(kingbase_conn,
						    mod_assoc,
							KCIResultGetColumnValue(result, i, ASSOC_ACCT),
						    slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_LFT)),
						    slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_RGT)),
						    ret_list, moved_parent);
				slurmdb_destroy_assoc_rec(mod_assoc);
				continue;
			}
			/* We do want to send all user accounts though */
			mod_assoc->shares_raw = NO_VAL;
			temp = KCIResultGetColumnValue(result, i, ASSOC_PART);
			if (temp != NULL && *temp != '\0'){
				// see if there is a partition name
				object = xstrdup_printf(
					"C = %-10s A = %-20s U = %-9s P = %s",
					assoc->cluster, KCIResultGetColumnValue(result, i, ASSOC_ACCT),
					KCIResultGetColumnValue(result, i, ASSOC_USER), KCIResultGetColumnValue(result, i, ASSOC_PART));
			} else {
				object = xstrdup_printf(
					"C = %-10s A = %-20s U = %-9s",
					assoc->cluster,
					KCIResultGetColumnValue(result, i, ASSOC_ACCT),
					KCIResultGetColumnValue(result, i, ASSOC_USER));
			}

			list_append(ret_list, object);
			object = NULL;

			if (moved_parent)
				slurmdb_destroy_assoc_rec(mod_assoc);
			else
				if (addto_update_list(kingbase_conn->update_list,
						      SLURMDB_MODIFY_ASSOC,
						      mod_assoc)
				    != SLURM_SUCCESS) {
					slurmdb_destroy_assoc_rec(
						mod_assoc);
					error("couldn't add to "
					      "the update list");
				}
		} else
			slurmdb_destroy_assoc_rec(mod_assoc);

	}
	KCIResultDealloc(result);

	return SLURM_SUCCESS;
}

/* when doing a select on this all the select should have a prefix of
 * t1. Returns "where" clause which needs to be xfreed. */
static char *_setup_assoc_cond_qos(slurmdb_assoc_cond_t *assoc_cond,
				   char *cluster_name)
{
	int set = 0;
	ListIterator itr = NULL;
	char *object = NULL;
	char *prefix = "t1";
	char *extra = NULL;

	/* Since this gets put in an SQL query we don't want it to be
	 * NULL since it would print (null) instead of nothing.
	 */
	if (!assoc_cond)
		return xstrdup("");

	/* we need to check this first so we can update the
	   with_sub_accts if needed since this the qos_list is a
	   parent thing
	*/
	if (assoc_cond->qos_list && list_count(assoc_cond->qos_list)) {
		/* we have to do the same thing as with_sub_accts does
		   first since we are looking for something that is
		   really most likely a parent thing */
		assoc_cond->with_sub_accts = 1;
		prefix = "t2";
		xstrfmtcat(extra, ", `%s_%s` as t2 where "
			   "(t1.lft between t2.lft and t2.rgt) and (",
			   cluster_name, assoc_table);
		set = 0;
		itr = list_iterator_create(assoc_cond->qos_list);
		while ((object = list_next(itr))) {
			if (set)
				xstrcat(extra, " or ");
			xstrfmtcat(extra,
				   "(%s.qos like '%%,%s' "
				   "or %s.qos like '%%,%s,%%' "
				   "or %s.delta_qos like '%%,+%s' "
				   "or %s.delta_qos like '%%,+%s,%%')",
				   prefix, object, prefix, object,
				   prefix, object, prefix, object);
			set = 1;
		}
		list_iterator_destroy(itr);
		xstrcat(extra, ") and");
	} else if (assoc_cond->with_sub_accts) {
		xstrfmtcat(extra, ", `%s_%s` as t2 where "
			   "(t1.lft between t2.lft and t2.rgt) and",
			   cluster_name, assoc_table);
	} else
		xstrcat(extra, " where");
	return extra;
}

/* When doing a select on this all the select should have a prefix of t1. */
#ifdef __METASTACK_OPT_LIST_USER
static int _setup_assoc_cond_limits(
	slurmdb_assoc_cond_t *assoc_cond,
	const char *prefix, char **extra, bool list_all)
#else
static int _setup_assoc_cond_limits(
	slurmdb_assoc_cond_t *assoc_cond,
	const char *prefix, char **extra)
#endif
{
	int set = 0;
	ListIterator itr = NULL;
	char *object = NULL;

	if (!assoc_cond)
		return 0;

	/*
	 * Don't use prefix here, always use t1 or we could get extra "deleted"
	 * entries we don't want.
	 */
	if (assoc_cond->with_deleted)
		xstrfmtcat(*extra, " (t1.deleted=0 or t1.deleted=1)");
	else
		xstrfmtcat(*extra, " t1.deleted=0");

	if (assoc_cond->only_defs) {
		set = 1;
		xstrfmtcat(*extra, " and (%s.is_def=1)", prefix);
	}

#ifdef __METASTACK_OPT_LIST_USER
	if (assoc_cond->acct_list && list_count(assoc_cond->acct_list) && !list_all) {
		set = 0;
		xstrcat(*extra, " and (");
		itr = list_iterator_create(assoc_cond->acct_list);
		while ((object = list_next(itr))) {
			if (set)
				xstrcat(*extra, " or ");
			xstrfmtcat(*extra, "%s.acct='%s'", prefix, object);
			set = 1;
		}
		list_iterator_destroy(itr);
		xstrcat(*extra, ")");
	}
#else
	if (assoc_cond->acct_list && list_count(assoc_cond->acct_list)) {
		set = 0;
		xstrcat(*extra, " and (");
		itr = list_iterator_create(assoc_cond->acct_list);
		while ((object = list_next(itr))) {
			if (set)
				xstrcat(*extra, " or ");
			xstrfmtcat(*extra, "%s.acct='%s'", prefix, object);
			set = 1;
		}
		list_iterator_destroy(itr);
		xstrcat(*extra, ")");
	}
#endif

	if (assoc_cond->def_qos_id_list
	    && list_count(assoc_cond->def_qos_id_list)) {
		set = 0;
		xstrcat(*extra, " and (");
		itr = list_iterator_create(assoc_cond->def_qos_id_list);
		while ((object = list_next(itr))) {
			if (set)
				xstrcat(*extra, " or ");
			xstrfmtcat(*extra, "%s.def_qos_id='%s'",
				   prefix, object);
			set = 1;
		}
		list_iterator_destroy(itr);
		xstrcat(*extra, ")");
	}

	if (assoc_cond->user_list && list_count(assoc_cond->user_list)) {
		set = 0;
		xstrcat(*extra, " and (");
		itr = list_iterator_create(assoc_cond->user_list);
		while ((object = list_next(itr))) {
			if (set)
				xstrcat(*extra, " or ");
			xstrfmtcat(*extra, "%s.user='%s'", prefix, object);
			set = 1;
		}
		list_iterator_destroy(itr);
		xstrcat(*extra, ")");
	} else if (assoc_cond->user_list) {
		/* we want all the users, but no non-user associations */
		set = 1;
		xstrfmtcat(*extra, " and (%s.user!='')", prefix);
	}

	if (assoc_cond->partition_list
	    && list_count(assoc_cond->partition_list)) {
		set = 0;
		xstrcat(*extra, " and (");
		itr = list_iterator_create(assoc_cond->partition_list);
		while ((object = list_next(itr))) {
			if (set)
				xstrcat(*extra, " or ");
			xstrfmtcat(*extra, "%s.partition='%s'",
				   prefix, object);
			set = 1;
		}
		list_iterator_destroy(itr);
		xstrcat(*extra, ")");
	}

	if (assoc_cond->id_list && list_count(assoc_cond->id_list)) {
		set = 0;
		xstrcat(*extra, " and (");
		itr = list_iterator_create(assoc_cond->id_list);
		while ((object = list_next(itr))) {
			if (set)
				xstrcat(*extra, " or ");
			xstrfmtcat(*extra, "%s.id_assoc=%s", prefix, object);
			set = 1;
		}
		list_iterator_destroy(itr);
		xstrcat(*extra, ")");
	}

	if (assoc_cond->parent_acct_list
	    && list_count(assoc_cond->parent_acct_list)) {
		set = 0;
		xstrcat(*extra, " and (");
		itr = list_iterator_create(assoc_cond->parent_acct_list);
		while ((object = list_next(itr))) {
			if (set)
				xstrcat(*extra, " or ");
			xstrfmtcat(*extra, "%s.parent_acct='%s'",
				   prefix, object);
			set = 1;
		}
		list_iterator_destroy(itr);
		xstrcat(*extra, ")");
	}
	return set;
}

static int _process_modify_assoc_results(kingbase_conn_t *kingbase_conn,
					 KCIResult *result,
					 slurmdb_assoc_rec_t *assoc,
					 slurmdb_user_rec_t *user,
					 char *cluster_name, char *sent_vals,
					 bool is_admin, bool same_user,
					 List ret_list)
{
	ListIterator itr = NULL;

	int added = 0;
	int rc = SLURM_SUCCESS;
	int set_qos_vals = 0;
	int moved_parent = 0;
	char *query = NULL, *vals = NULL, *object = NULL, *name_char = NULL;
	char *reset_query = NULL;
	time_t now = time(NULL);
    char *with_assoc_sql[14] = { NULL };
	xassert(result);

	if (!KCIResultGetRowCount(result))
		return SLURM_SUCCESS;

	vals = xstrdup(sent_vals);
	for(int i = 0; i < KCIResultGetRowCount(result); i++){
		KCIResult *result2 = NULL;
		slurmdb_assoc_rec_t *mod_assoc = NULL, alt_assoc;
		int account_type=0;
		/* If parent changes these also could change
		   so we need to keep track of the latest
		   ones.
		*/
		uint32_t lft = slurm_atoul(KCIResultGetColumnValue(result, i, MASSOC_LFT));
		uint32_t rgt = slurm_atoul(KCIResultGetColumnValue(result, i, MASSOC_RGT));
		char *orig_acct, *account;

		orig_acct = account = KCIResultGetColumnValue(result, i, MASSOC_ACCT);

		slurmdb_init_assoc_rec(&alt_assoc, 0);

		/* Here we want to see if the person
		 * is a coord of the parent account
		 * since we don't want him to be able
		 * to alter the limits of the account
		 * he is directly coord of.  They
		 * should be able to alter the
		 * sub-accounts though. If no parent account
		 * that means we are talking about a user
		 * association so account is really the parent
		 * of the user a coord can change that all day long.
		 */
		char *temp = KCIResultGetColumnValue(result, i, MASSOC_PACCT);
		if(temp != NULL && *temp != '\0')
			account = temp;

		/* If this is the same user all has been done
		   previously to make sure the user is only changing
		   things they are allowed to change.
		*/
		if (!is_admin && !same_user) {
			slurmdb_coord_rec_t *coord = NULL;

			if (!user->coord_accts) { // This should never
				// happen
				error("We are here with no coord accts.");
				rc = ESLURM_ACCESS_DENIED;
				goto end_it;
			}
			itr = list_iterator_create(user->coord_accts);
			while ((coord = list_next(itr))) {
				if (!xstrcasecmp(coord->name, account))
					break;
			}
			list_iterator_destroy(itr);

			if (!coord) {
				char *temp = KCIResultGetColumnValue(result, i, MASSOC_PACCT);
				if (*temp != '\0')
					error("User %s(%d) can not modify "
					      "account (%s) because they "
					      "are not coordinators of "
					      "parent account '%s'.",
					      user->name, user->uid,
					      KCIResultGetColumnValue(result, i, MASSOC_ACCT),
					      KCIResultGetColumnValue(result, i, MASSOC_PACCT));
				else
					error("User %s(%d) does not have the "
					      "ability to modify the account "
					      "(%s).",
					      user->name, user->uid,
					      KCIResultGetColumnValue(result, i, MASSOC_ACCT));

				rc = ESLURM_ACCESS_DENIED;
				goto end_it;
			} else if (_check_coord_qos(kingbase_conn, cluster_name,
						    account, user->name,
						    assoc->qos_list)
				   == SLURM_ERROR) {
				assoc_mgr_lock_t locks = {
					NO_LOCK, NO_LOCK, READ_LOCK, NO_LOCK,
					NO_LOCK, NO_LOCK, NO_LOCK };
				char *requested_qos;

				assoc_mgr_lock(&locks);
				requested_qos = get_qos_complete_str(
					assoc_mgr_qos_list, assoc->qos_list);
				assoc_mgr_unlock(&locks);
				error("Coordinator %s(%d) does not have the "
				      "access to all the qos requested (%s), "
				      "so they can't modify account "
				      "%s with it.",
				      user->name, user->uid, requested_qos,
				      account);
				xfree(requested_qos);
				rc = ESLURM_ACCESS_DENIED;
				goto end_it;
			}
		}
		temp = KCIResultGetColumnValue(result, i, MASSOC_PART);
		char *temp2 = KCIResultGetColumnValue(result, i, MASSOC_USER);
		if (*temp != '\0') {
			// see if there is a partition name
			object = xstrdup_printf(
				"C = %-10s A = %-20s U = %-9s P = %s",
				cluster_name, KCIResultGetColumnValue(result, i, MASSOC_ACCT),
				KCIResultGetColumnValue(result, i, MASSOC_USER), temp);
		} else if (*temp2 != '\0'){
			object = xstrdup_printf(
				"C = %-10s A = %-20s U = %-9s",
				cluster_name, KCIResultGetColumnValue(result, i, MASSOC_ACCT),
				temp2);
		} else {
			if (assoc->parent_acct) {
				if (!xstrcasecmp(KCIResultGetColumnValue(result, i, MASSOC_ACCT),
						assoc->parent_acct)) {
					error("You can't make an account be a "
					      "child of it's self");
					continue;
				}
				rc = _move_parent(kingbase_conn, user->uid,
						  &lft, &rgt,
						  cluster_name,
						  KCIResultGetColumnValue(result, i, MASSOC_ID),
						  KCIResultGetColumnValue(result, i, MASSOC_PACCT),
						  assoc->parent_acct,
						  now);

				if ((rc == ESLURM_INVALID_PARENT_ACCOUNT)
				    || (rc == ESLURM_SAME_PARENT_ACCOUNT)) {
					continue;
				} else if (rc != SLURM_SUCCESS)
					break;

				moved_parent = 1;
			}
			char *temp = KCIResultGetColumnValue(result, i, MASSOC_PACCT);
			if (*temp != '\0') {
				object = xstrdup_printf(
					"C = %-10s A = %s of %s",
					cluster_name, KCIResultGetColumnValue(result, i, MASSOC_ACCT),
					temp);
			} else {
				object = xstrdup_printf(
					"C = %-10s A = %s",
					cluster_name, KCIResultGetColumnValue(result, i, MASSOC_ACCT));
			}
			account_type = 1;
		}
		list_append(ret_list, object);
		object = NULL;
		added++;

		if (name_char)
			xstrfmtcat(name_char, " or id_assoc=%s",
				   KCIResultGetColumnValue(result, i, MASSOC_ID));
		else
			xstrfmtcat(name_char, "(id_assoc=%s", KCIResultGetColumnValue(result, i, MASSOC_ID));

		/* Only do this when not dealing with the root association. */
		if (xstrcmp(orig_acct, "root") || KCIResultGetColumnValue(result, i, MASSOC_USER)[0]) {
            int tmp_count=_get_parend(result2, account,query,cluster_name ,assoc_table, kingbase_conn, with_assoc_sql, 0);
			if (tmp_count > 0) {
				if (assoc->def_qos_id == INFINITE
				    && (with_assoc_sql[ASSOC2_REQ_DEF_QOS] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_DEF_QOS])))
					alt_assoc.def_qos_id = slurm_atoul(
						with_assoc_sql[ASSOC2_REQ_DEF_QOS]);

				if ((assoc->max_jobs == INFINITE)
				    && (with_assoc_sql[ASSOC2_REQ_MJ] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MJ])))
					alt_assoc.max_jobs = slurm_atoul(
						with_assoc_sql[ASSOC2_REQ_MJ]);
				if ((assoc->max_jobs_accrue == INFINITE)
				    && (with_assoc_sql[ASSOC2_REQ_MJA] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MJA])))
					alt_assoc.max_jobs_accrue = slurm_atoul(
						with_assoc_sql[ASSOC2_REQ_MJA]);
				if ((assoc->min_prio_thresh == INFINITE)
				    && (with_assoc_sql[ASSOC2_REQ_MPT] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MPT])))
					alt_assoc.min_prio_thresh = slurm_atoul(
						with_assoc_sql[ASSOC2_REQ_MPT]);
				if ((assoc->max_submit_jobs == INFINITE)
				    && (with_assoc_sql[ASSOC2_REQ_MSJ] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MSJ])))
					alt_assoc.max_submit_jobs = slurm_atoul(
						with_assoc_sql[ASSOC2_REQ_MSJ]);
				if ((assoc->max_wall_pj == INFINITE)
				    && (with_assoc_sql[ASSOC2_REQ_MWPJ] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MWPJ])))
					alt_assoc.max_wall_pj = slurm_atoul(
						with_assoc_sql[ASSOC2_REQ_MWPJ]);
				if ((assoc->priority == INFINITE)
				    && (with_assoc_sql[ASSOC2_REQ_PRIO] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_PRIO])))
					alt_assoc.priority = slurm_atoul(
						with_assoc_sql[ASSOC2_REQ_PRIO]);

				/* We don't have to copy these strings
				 * or check for there existance,
				 * slurmdb_combine_tres_strings will
				 * do this for us below.
				 */
				if ((with_assoc_sql[ASSOC2_REQ_MTPJ] != NULL) &&  (strlen(with_assoc_sql[ASSOC2_REQ_MTPJ])))
					alt_assoc.max_tres_pj =
						with_assoc_sql[ASSOC2_REQ_MTPJ];
				if ((with_assoc_sql[ASSOC2_REQ_MTPN] != NULL) &&  (strlen(with_assoc_sql[ASSOC2_REQ_MTPN])))
					alt_assoc.max_tres_pn =
						with_assoc_sql[ASSOC2_REQ_MTPN];
				if ((with_assoc_sql[ASSOC2_REQ_MTMPJ] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MTMPJ])))
					alt_assoc.max_tres_mins_pj =
						with_assoc_sql[ASSOC2_REQ_MTMPJ];
				if ((with_assoc_sql[ASSOC2_REQ_MTRM] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MTRM])))
					alt_assoc.max_tres_run_mins =
						with_assoc_sql[ASSOC2_REQ_MTRM];
			}
			for(int j =0 ; j < 14; j++) {
				if(with_assoc_sql[j])
				xfree(with_assoc_sql[j]);
			}
		}
		mod_assoc = xmalloc(sizeof(slurmdb_assoc_rec_t));
		slurmdb_init_assoc_rec(mod_assoc, 0);
		mod_assoc->id = slurm_atoul(KCIResultGetColumnValue(result, i, MASSOC_ID));
		mod_assoc->cluster = xstrdup(cluster_name);

		if (alt_assoc.def_qos_id != NO_VAL)
			mod_assoc->def_qos_id = alt_assoc.def_qos_id;
		else
			mod_assoc->def_qos_id = assoc->def_qos_id;

		mod_assoc->is_def = assoc->is_def;

		mod_assoc->shares_raw = assoc->shares_raw;

		mod_tres_str(&mod_assoc->grp_tres,
			     assoc->grp_tres, KCIResultGetColumnValue(result, i, MASSOC_GT),
			     NULL, "grp_tres", &vals, mod_assoc->id, 1);
		mod_tres_str(&mod_assoc->grp_tres_mins,
			     assoc->grp_tres_mins, KCIResultGetColumnValue(result, i, MASSOC_GTM),
			     NULL, "grp_tres_mins", &vals, mod_assoc->id, 1);
		mod_tres_str(&mod_assoc->grp_tres_run_mins,
			     assoc->grp_tres_run_mins, KCIResultGetColumnValue(result, i, MASSOC_GTRM),
			     NULL, "grp_tres_run_mins", &vals,
			     mod_assoc->id, 1);

		mod_assoc->grp_jobs = assoc->grp_jobs;
		mod_assoc->grp_jobs_accrue = assoc->grp_jobs_accrue;
		mod_assoc->grp_submit_jobs = assoc->grp_submit_jobs;
		mod_assoc->grp_wall = assoc->grp_wall;

		mod_tres_str(&mod_assoc->max_tres_pj,
			     assoc->max_tres_pj, KCIResultGetColumnValue(result, i, MASSOC_MTPJ),
			     alt_assoc.max_tres_pj, "max_tres_pj",
			     &vals, mod_assoc->id, 1);
		mod_tres_str(&mod_assoc->max_tres_pn,
			     assoc->max_tres_pn, KCIResultGetColumnValue(result, i, MASSOC_MTPN),
			     alt_assoc.max_tres_pn, "max_tres_pn",
			     &vals, mod_assoc->id, 1);
		mod_tres_str(&mod_assoc->max_tres_mins_pj,
			     assoc->max_tres_mins_pj, KCIResultGetColumnValue(result, i, MASSOC_MTMPJ),
			     alt_assoc.max_tres_mins_pj, "max_tres_mins_pj",
			     &vals, mod_assoc->id, 1);
		mod_tres_str(&mod_assoc->max_tres_run_mins,
			     assoc->max_tres_run_mins, KCIResultGetColumnValue(result, i, MASSOC_MTRM),
			     alt_assoc.max_tres_run_mins, "max_tres_run_mins",
			     &vals, mod_assoc->id, 1);

		if (result2)
			KCIResultDealloc(result2);

		if (alt_assoc.max_jobs != NO_VAL)
			mod_assoc->max_jobs = alt_assoc.max_jobs;
		else
			mod_assoc->max_jobs = assoc->max_jobs;
		if (alt_assoc.max_jobs_accrue != NO_VAL)
			mod_assoc->max_jobs_accrue = alt_assoc.max_jobs_accrue;
		else
			mod_assoc->max_jobs_accrue = assoc->max_jobs_accrue;
		if (alt_assoc.min_prio_thresh != NO_VAL)
			mod_assoc->min_prio_thresh = alt_assoc.min_prio_thresh;
		else
			mod_assoc->min_prio_thresh = assoc->min_prio_thresh;
		if (alt_assoc.max_submit_jobs != NO_VAL)
			mod_assoc->max_submit_jobs = alt_assoc.max_submit_jobs;
		else
			mod_assoc->max_submit_jobs = assoc->max_submit_jobs;
		if (alt_assoc.max_wall_pj != NO_VAL)
			mod_assoc->max_wall_pj = alt_assoc.max_wall_pj;
		else
			mod_assoc->max_wall_pj = assoc->max_wall_pj;
		if (alt_assoc.priority != NO_VAL)
			mod_assoc->priority = alt_assoc.priority;
		else
			mod_assoc->priority = assoc->priority;

		/* no need to get the parent id since if we moved
		 * parent id's we will get it when we send the total list */
		temp = KCIResultGetColumnValue(result, i, MASSOC_USER);
		if (*temp == '\0')
			mod_assoc->parent_acct = xstrdup(assoc->parent_acct);
		if (assoc->qos_list && list_count(assoc->qos_list)) {
			ListIterator new_qos_itr =
				list_iterator_create(assoc->qos_list);
			char *new_qos = NULL, *tmp_qos = NULL;
			bool adding_straight = 0;

			mod_assoc->qos_list = list_create(xfree_ptr);

			while ((new_qos = list_next(new_qos_itr))) {
				if (new_qos[0] == '-' || new_qos[0] == '+') {
					list_append(mod_assoc->qos_list,
						    xstrdup(new_qos));
				} else if (new_qos[0]) {
					list_append(mod_assoc->qos_list,
						    xstrdup_printf("=%s",
								   new_qos));
				}

				if (set_qos_vals)
					continue;
				/* Now we can set up the values and
				   make sure we aren't over writing
				   things that are really from the
				   parent
				*/
				if (new_qos[0] == '-') {
					xstrfmtcat(vals,
						   ", qos=if (qos='', '', "
						   "replace(replace("
						   "qos, ',%s,', ','), "
						   "',,', ','))"
						   ", qos=if (qos=',', '', qos)"
						   ", delta_qos=if (qos='', "
						   "replace(concat(replace("
						   "replace("
						   "delta_qos, ',+%s,', ','), "
						   "',-%s,', ','), "
						   "',%s,'), ',,', ','), '')",
						   new_qos+1, new_qos+1,
						   new_qos+1, new_qos);
				} else if (new_qos[0] == '+') {
					xstrfmtcat(vals,
						   ", qos=if (qos='', '', "
						   "replace(concat("
						   "replace(qos, ',%s,', ','), "
						   "',%s,'), ',,', ',')), "
						   "delta_qos=if ("
						   "qos='', replace(concat("
						   "replace(replace("
						   "delta_qos, ',+%s,', ','), "
						   "',-%s,', ','), "
						   "',%s,'), ',,', ','), '')",
						   new_qos+1, new_qos+1,
						   new_qos+1, new_qos+1,
						   new_qos);
				} else if (new_qos[0]) {
					xstrfmtcat(tmp_qos, ",%s", new_qos);
					adding_straight = 1;
				} else
					xstrcat(tmp_qos, "");

			}
			list_iterator_destroy(new_qos_itr);

			if (!set_qos_vals && tmp_qos) {
				xstrfmtcat(vals, ", qos='%s%s', delta_qos=''",
					   tmp_qos, adding_straight ? "," : "");
			}
			xfree(tmp_qos);

			set_qos_vals = 1;
		}


		if (account_type) {
			_modify_unset_users(kingbase_conn,
					    mod_assoc,
					    KCIResultGetColumnValue(result, i, MASSOC_ACCT),
					    lft, rgt,
					    ret_list,
					    moved_parent);
		} else if ((assoc->is_def == 1) && KCIResultGetColumnValue(result, i, MASSOC_USER)[0]) {
			/* Use fresh one here so we don't have to
			   worry about dealing with bad values.
			*/
			slurmdb_assoc_rec_t tmp_assoc;
			slurmdb_init_assoc_rec(&tmp_assoc, 0);
			tmp_assoc.is_def = 1;
			tmp_assoc.cluster = cluster_name;
			tmp_assoc.acct = KCIResultGetColumnValue(result, i, MASSOC_ACCT);
			tmp_assoc.user = KCIResultGetColumnValue(result, i, MASSOC_USER);
			if ((rc = _reset_default_assoc(
				     kingbase_conn, &tmp_assoc, &reset_query,
				     moved_parent ? 0 : 1))
			    != SLURM_SUCCESS) {
				slurmdb_destroy_assoc_rec(mod_assoc);
				xfree(reset_query);
				goto end_it;
			}
		}

		if (!vals || !vals[0] || moved_parent)
			slurmdb_destroy_assoc_rec(mod_assoc);
		else if (addto_update_list(kingbase_conn->update_list,
					   SLURMDB_MODIFY_ASSOC,
					   mod_assoc) != SLURM_SUCCESS) {
			error("couldn't add to the update list");
			slurmdb_destroy_assoc_rec(mod_assoc);
		}
	}

	xstrcat(name_char, ")");

	if (assoc->parent_acct) {
		if (((rc == ESLURM_INVALID_PARENT_ACCOUNT)
		     || (rc == ESLURM_SAME_PARENT_ACCOUNT))
		    && added)
			rc = SLURM_SUCCESS;
	}

	if (rc != SLURM_SUCCESS)
		goto end_it;

	if (vals && vals[0]) {
		char *user_name = uid_to_string((uid_t) user->uid);
		rc = modify_common(kingbase_conn, DBD_MODIFY_ASSOCS, now,
				   user_name, assoc_table, name_char, vals,
				   cluster_name);
		xfree(user_name);
		if (rc == SLURM_ERROR) {
			error("Couldn't modify associations");
			goto end_it;
		}
	}

	if (moved_parent) {
		List local_assoc_list = NULL;
		slurmdb_assoc_cond_t local_assoc_cond;
		/* now we need to send the update of the new parents and
		 * limits, so just to be safe, send the whole
		 * tree because we could have some limits that
		 * were affected but not noticed.
		 */
		/* we can probably just look at the mod time now but
		 * we will have to wait for the next revision number
		 * since you can't query on mod time here and I don't
		 * want to rewrite code to make it happen
		 */

		memset(&local_assoc_cond, 0,
		       sizeof(slurmdb_assoc_cond_t));
		local_assoc_cond.cluster_list = list_create(NULL);
		list_append(local_assoc_cond.cluster_list, cluster_name);
#ifdef __METASTACK_OPT_LIST_USER
		local_assoc_list = as_kingbase_get_assocs(
			kingbase_conn, user->uid, &local_assoc_cond, false);
#else		
		local_assoc_list = as_kingbase_get_assocs(
			kingbase_conn, user->uid, &local_assoc_cond);
#endif
		FREE_NULL_LIST(local_assoc_cond.cluster_list);
		if (!local_assoc_list)
			goto end_it;


		_move_assoc_list_to_update_list(kingbase_conn->update_list,
						local_assoc_list);
		FREE_NULL_LIST(local_assoc_list);
	}

	if (reset_query) {
		DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", reset_query);
		//info("[query] line %d, %s: query: %s", __LINE__, __func__, reset_query);
		fetch_flag_t *fetch_flag = NULL;
		fetch_result_t *data_rt = NULL;
		fetch_flag = set_fetch_flag(false, false, false);
		data_rt = xmalloc(sizeof(fetch_result_t));
		rc = kingbase_for_fetch(kingbase_conn, reset_query, fetch_flag, data_rt);
		free_res_data(data_rt, fetch_flag);
		if(rc == SLURM_ERROR) {
			error("Couldn't update defaults");
		}
	}
end_it:
	xfree(reset_query);
	xfree(name_char);
	xfree(vals);

	return rc;
}

static int _process_remove_assoc_results(kingbase_conn_t *kingbase_conn,
					 KCIResult *result,
					 slurmdb_user_rec_t *user,
					 char *cluster_name,
					 char *name_char,
					 bool is_admin, List ret_list,
					 bool *jobs_running,
					 bool *default_account)
{
	ListIterator itr = NULL;

	int rc = SLURM_SUCCESS;
	char *assoc_char = NULL, *object = NULL;
	time_t now = time(NULL);
	char *user_name = NULL;
	uint32_t smallest_lft = 0xFFFFFFFF;

	xassert(result);
	if (*jobs_running || *default_account)
		goto skip_process;

	for(int i = 0; i < KCIResultGetRowCount(result); i++){
		slurmdb_assoc_rec_t *rem_assoc = NULL;
		uint32_t lft;

		if (!is_admin) {
			slurmdb_coord_rec_t *coord = NULL;
			if (!user->coord_accts) { // This should never
				// happen
				error("We are here with no coord accts");
				rc = ESLURM_ACCESS_DENIED;
				goto end_it;
			}
			itr = list_iterator_create(user->coord_accts);
			while ((coord = list_next(itr))) {
				if (!xstrcasecmp(coord->name,
						KCIResultGetColumnValue(result, i, RASSOC_ACCT)))
					break;
			}
			list_iterator_destroy(itr);

			if (!coord) {
				error("User %s(%d) does not have the "
				      "ability to change this account (%s)",
				      user->name, user->uid, KCIResultGetColumnValue(result, i, RASSOC_ACCT));
				rc = ESLURM_ACCESS_DENIED;
				goto end_it;
			}
		}
		char *temp = KCIResultGetColumnValue(result, i, RASSOC_PART);
		char *temp2 = KCIResultGetColumnValue(result, i, RASSOC_USER);
		if (*temp != '\0') {
			// see if there is a partition name
			object = xstrdup_printf(
				"C = %-10s A = %-10s U = %-9s P = %s",
				cluster_name, KCIResultGetColumnValue(result, i, RASSOC_ACCT),
				KCIResultGetColumnValue(result, i, RASSOC_USER), temp);
		} else if (*temp2 != '\0'){
			object = xstrdup_printf(
				"C = %-10s A = %-10s U = %-9s",
				cluster_name, KCIResultGetColumnValue(result, i, RASSOC_ACCT),
				temp2);
		} else {
			char *temp = KCIResultGetColumnValue(result, i, RASSOC_PACCT);
			if (*temp != '\0') {
				object = xstrdup_printf(
					"C = %-10s A = %s of %s",
					cluster_name, KCIResultGetColumnValue(result, i, RASSOC_ACCT),
					temp);
			} else {
				object = xstrdup_printf(
					"C = %-10s A = %s",
					cluster_name, KCIResultGetColumnValue(result, i, RASSOC_ACCT));
			}
		}
		list_append(ret_list, object);
		if (assoc_char)
			xstrfmtcat(assoc_char, " or id_assoc=%s",
				   KCIResultGetColumnValue(result, i, RASSOC_ID));
		else
			xstrfmtcat(assoc_char, "id_assoc=%s", KCIResultGetColumnValue(result, i, RASSOC_ID));

		/* get the smallest lft here to be able to send all
		   the modified lfts after it.
		*/
		lft = slurm_atoul(KCIResultGetColumnValue(result, i, RASSOC_LFT));
		if (lft < smallest_lft)
			smallest_lft = lft;

		rem_assoc = xmalloc(sizeof(slurmdb_assoc_rec_t));
		slurmdb_init_assoc_rec(rem_assoc, 0);
		rem_assoc->flags |= ASSOC_FLAG_DELETED;
		rem_assoc->id = slurm_atoul(KCIResultGetColumnValue(result, i, RASSOC_ID));
		rem_assoc->cluster = xstrdup(cluster_name);
		if (addto_update_list(kingbase_conn->update_list,
				      SLURMDB_REMOVE_ASSOC,
				      rem_assoc) != SLURM_SUCCESS) {
			slurmdb_destroy_assoc_rec(rem_assoc);
			error("couldn't add to the update list");
		}

	}

	if ((rc = as_kingbase_get_modified_lfts(
		     kingbase_conn, cluster_name, smallest_lft)) != SLURM_SUCCESS)
		goto end_it;


skip_process:
	user_name = uid_to_string((uid_t) user->uid);

	rc = remove_common(kingbase_conn, DBD_REMOVE_ASSOCS, now, user_name,
			   assoc_table, name_char, assoc_char, cluster_name,
			   ret_list, jobs_running, default_account);
end_it:
	xfree(user_name);
	xfree(assoc_char);

	return rc;
}


static int _cluster_get_assocs(kingbase_conn_t *kingbase_conn,
			       slurmdb_user_rec_t *user,
			       slurmdb_assoc_cond_t *assoc_cond,
			       char *cluster_name,
			       char *fields, char *sent_extra,
			       bool is_admin, List sent_list)
{
	List assoc_list;
	List delta_qos_list = NULL;
	ListIterator itr = NULL;
	KCIResult *result = NULL;
	uint32_t parent_def_qos_id = 0;
	uint32_t parent_mj = INFINITE;
	uint32_t parent_mja = INFINITE;
	uint32_t parent_mpt = INFINITE;
	uint32_t parent_msj = INFINITE;
	uint32_t parent_mwpj = INFINITE;
	uint32_t parent_prio = INFINITE;
	char *parent_mtpj = NULL;
	char *parent_mtpn = NULL;
	char *parent_mtmpj = NULL;
	char *parent_mtrm = NULL;
	char *parent_acct = NULL;
	char *parent_qos = NULL;
	char *parent_delta_qos = NULL;
	char *last_acct = NULL;
	char *last_cluster = NULL;
	uint32_t parent_id = 0;
	char *query = NULL;
	char *extra = xstrdup(sent_extra);
	char *qos_extra = NULL;

	/* needed if we don't have an assoc_cond */
	uint16_t without_parent_info = 0;
	uint16_t without_parent_limits = 0;
	uint16_t with_usage = 0;
	uint16_t with_raw_qos = 0;

    char *with_assoc_sql[14] = {NULL};
	if (assoc_cond) {
		with_raw_qos = assoc_cond->with_raw_qos;
		with_usage = assoc_cond->with_usage;
#ifdef __METASTACK_OPT_LIST_USER
        if (assoc_cond->without_parent_limits != 2)
		    without_parent_limits = assoc_cond->without_parent_limits;
#else
		without_parent_limits = assoc_cond->without_parent_limits;
#endif
		without_parent_info = assoc_cond->without_parent_info;
	}

	/* this is here to make sure we are looking at only this user
	 * if this flag is set.  We also include any accounts they may be
	 * coordinator of.
	 */
	if (!is_admin && (slurm_conf.private_data & PRIVATE_DATA_USERS)) {
		int set = 0;
		query = xstrdup_printf("select lft from `%s_%s` where `user`='%s'",
				       cluster_name, assoc_table, user->name);
		if (user->coord_accts) {
			slurmdb_coord_rec_t *coord = NULL;
			itr = list_iterator_create(user->coord_accts);
			while ((coord = list_next(itr))) {
				xstrfmtcat(query, " or acct='%s'",
					   coord->name);
			}
			list_iterator_destroy(itr);
		}
		DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", query);
		//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);
		result = kingbase_db_query_ret(kingbase_conn, query, 0);
		if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK) {
			KCIResultDealloc(result);
			xfree(extra);
			xfree(query);
			return SLURM_ERROR;
		}
		xfree(query);
		set = 0;
		int count_tmp= KCIResultGetRowCount(result);
		for(int i = 0; i < count_tmp; i++){
			if (set) {
				xstrfmtcat(extra,
					   " or (%s between t1.lft and t1.rgt)",
					   KCIResultGetColumnValue(result, i, 0));
			} else {
				set = 1;
				xstrfmtcat(extra,
					   " and ((%s between t1.lft and t1.rgt)",
					   KCIResultGetColumnValue(result, i, 0));
			}
		}

		KCIResultDealloc(result);

		if (set)
			xstrcat(extra, ")");
		else {
			xfree(extra);
			debug("User %s has no associations, and is not admin, "
			      "so not returning any.", user->name);
			/* This user has no valid associations, so
			 * end. */
			return SLURM_SUCCESS;
		}
	}

	qos_extra = _setup_assoc_cond_qos(assoc_cond, cluster_name);


	//START_TIMER;
	query = xstrdup_printf("select distinct %s from `%s_%s` as t1%s%s "
			       "order by lft;",
			       fields, cluster_name, assoc_table,
			       qos_extra, extra);
	xfree(qos_extra);
	xfree(extra);
	DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", query);
	//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);
	result = kingbase_db_query_ret(kingbase_conn, query, 0);
	if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK) {
		KCIResultDealloc(result);
		xfree(query);
		if (strstr(KCIConnectionGetLastError(kingbase_conn->db_conn),"不存在")
			|| strstr(KCIConnectionGetLastError(kingbase_conn->db_conn),"not exist"))
			return SLURM_SUCCESS;
		else
			return SLURM_ERROR;
	}
	xfree(query);

	if (!KCIResultGetRowCount(result)) {
		KCIResultDealloc(result);
		return SLURM_SUCCESS;
	}

	assoc_list = list_create(slurmdb_destroy_assoc_rec);
	delta_qos_list = list_create(xfree_ptr);
#ifdef __METASTACK_OPT_LIST_USER
	if (assoc_cond->without_parent_limits == 2) {
		int count_tmp = KCIResultGetRowCount(result);
		for(int i = 0; i < count_tmp; i++) {
			slurmdb_assoc_rec_t *assoc =xmalloc(sizeof(slurmdb_assoc_rec_t));

			char *tmp = NULL;
			uint16_t deleted = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_DELETED));
			list_append(assoc_list, assoc);
			assoc->id = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_ID));
			assoc->is_def = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_DEFAULT));

			if (deleted)
				assoc->flags |= ASSOC_FLAG_DELETED;

			assoc->lft = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_LFT));
			assoc->rgt = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_RGT));

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_USER);
			if (*tmp !='\0')
				assoc->user = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_USER));
			assoc->acct = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_ACCT));
			assoc->cluster = xstrdup(cluster_name);

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GJ);
			if ( *tmp != '\0')
				assoc->grp_jobs = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_GJ));
			else
				assoc->grp_jobs = INFINITE;

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GJA);
			if (*tmp != '\0')
				assoc->grp_jobs_accrue =
					slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_GJA));
			else
				assoc->grp_jobs_accrue = INFINITE;
			
			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GSJ);
			if (*tmp != '\0')
				assoc->grp_submit_jobs =
					slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_GSJ));
			else
				assoc->grp_submit_jobs = INFINITE;
			
			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GW);
			if (*tmp != '\0')
				assoc->grp_wall = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_GW));
			else
				assoc->grp_wall = INFINITE;

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GT);
			if (*tmp != '\0')
				assoc->grp_tres = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_GT));
			
			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GTM);
			if (*tmp != '\0')
				assoc->grp_tres_mins = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_GTM));
			
			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GTRM);
			if (*tmp != '\0')
				assoc->grp_tres_run_mins = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_GTRM));

			parent_acct = KCIResultGetColumnValue(result, i, ASSOC_REQ_ACCT);

			tmp =KCIResultGetColumnValue(result, i, ASSOC_REQ_PARENT);
			if (!without_parent_info
				&& (*tmp != '\0') ) {
				assoc->parent_acct = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_PARENT));
				parent_acct = KCIResultGetColumnValue(result, i, ASSOC_REQ_PARENT);
			} else if (!assoc->user) {
				/* This is the root association so we have no
				parent id */
				parent_acct = NULL;
				parent_id = 0;
			}

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_PART);
			if (*tmp != '\0')
				assoc->partition = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_PART));

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_FS);
			if (*tmp != '\0')
				assoc->shares_raw = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_FS));
			else
				assoc->shares_raw = 1;

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_DEF_QOS);
			if (*tmp != '\0')
				assoc->def_qos_id = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_DEF_QOS));
			else
				assoc->def_qos_id = parent_def_qos_id;

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MJ);
			if (*tmp != '\0')
				assoc->max_jobs = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_MJ));
			else
				assoc->max_jobs = parent_mj;

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MJA);
			if (*tmp != '\0')
				assoc->max_jobs_accrue =
					slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_MJA));
			else
				assoc->max_jobs_accrue = parent_mja;
			
			tmp= KCIResultGetColumnValue(result, i, ASSOC_REQ_MPT);
			if (*tmp != '\0')
				assoc->min_prio_thresh = slurm_atoul(
					KCIResultGetColumnValue(result, i, ASSOC_REQ_MPT));
			else
				assoc->min_prio_thresh = parent_mpt;

			tmp =KCIResultGetColumnValue(result, i, ASSOC_REQ_MSJ);
			if (*tmp != '\0')
				assoc->max_submit_jobs = slurm_atoul(
					KCIResultGetColumnValue(result, i, ASSOC_REQ_MSJ));
			else
				assoc->max_submit_jobs = parent_msj;

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MWPJ);
			if (*tmp != '\0')
				assoc->max_wall_pj = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_MWPJ));
			else
				assoc->max_wall_pj = parent_mwpj;

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_PRIO);
			if (*tmp != '\0')
				assoc->priority = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_PRIO));
			else
				assoc->priority = parent_prio;
			
			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MTPJ);
			if (*tmp != '\0')
				assoc->max_tres_pj = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_MTPJ));

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MTPN);
			if (*tmp != '\0')
				assoc->max_tres_pn = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_MTPN));

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MTMPJ);
			if (*tmp != '\0')
				assoc->max_tres_mins_pj = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_MTMPJ));

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MTRM);
			if (*tmp != '\0')
				assoc->max_tres_run_mins = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_MTRM));

			/* For the tres limits we just concatted the limits going up
			* the hierarchy slurmdb_tres_list_from_string will just skip
			* over any reoccuring limit to give us the first one per
			* TRES.
			*/
			slurmdb_combine_tres_strings(
				&assoc->max_tres_pj, parent_mtpj,
				TRES_STR_FLAG_SORT_ID);
			slurmdb_combine_tres_strings(
				&assoc->max_tres_pn, parent_mtpn,
				TRES_STR_FLAG_SORT_ID);
			slurmdb_combine_tres_strings(
				&assoc->max_tres_mins_pj, parent_mtmpj,
				TRES_STR_FLAG_SORT_ID);
			slurmdb_combine_tres_strings(
				&assoc->max_tres_run_mins, parent_mtrm,
				TRES_STR_FLAG_SORT_ID);

			assoc->qos_list = list_create(xfree_ptr);

			/* do a plus 1 since a comma is the first thing there
			* in the list.  Also you can never have both a qos
			* and a delta qos so if you have a qos don't worry
			* about the delta.
			*/
			tmp = KCIResultGetColumnValue(result, i,ASSOC_REQ_QOS);
			debug("KCIResultGetColumnValue(result, i,ASSOC_REQ_QOS)[%d]=%s",i,KCIResultGetColumnValue(result, i,ASSOC_REQ_QOS));
			if (*tmp != '\0')
				slurm_addto_char_list(assoc->qos_list,
							KCIResultGetColumnValue(result, i,ASSOC_REQ_QOS)+1);
			else {
				/* if qos is set on the association itself do
				not worry about the deltas
				*/

				/* add the parents first */
				if (parent_qos)
					slurm_addto_char_list(assoc->qos_list,
								parent_qos+1);

				/* then add the parents delta */
				if (parent_delta_qos)
					slurm_addto_char_list(delta_qos_list,
								parent_delta_qos+1);

				/* now add the associations */ 
				tmp = KCIResultGetColumnValue(result, i,ASSOC_REQ_DELTA_QOS);
				
				if (*tmp != '\0')
					slurm_addto_char_list(
						delta_qos_list,
						KCIResultGetColumnValue(result, i,ASSOC_REQ_DELTA_QOS)+1);
			}

			/* Sometimes we want to see exactly what is here in
			the database instead of a complete list.  This will
			give it to us.
			*/
			if (with_raw_qos && list_count(delta_qos_list)) {
				list_transfer(assoc->qos_list, delta_qos_list);
				list_flush(delta_qos_list);
			} else if (list_count(delta_qos_list)) {
				ListIterator curr_qos_itr =
					list_iterator_create(assoc->qos_list);
				ListIterator new_qos_itr =
					list_iterator_create(delta_qos_list);
				char *new_qos = NULL, *curr_qos = NULL;

				while ((new_qos = list_next(new_qos_itr))) {
					if (new_qos[0] == '-') {
						while ((curr_qos =
							list_next(curr_qos_itr))) {
							if (!xstrcmp(curr_qos,
									new_qos+1)) {
								list_delete_item(
									curr_qos_itr);
								break;
							}
						}
						list_iterator_reset(curr_qos_itr);
					} else if (new_qos[0] == '+') {
						while ((curr_qos =
							list_next(curr_qos_itr))) {
							if (!xstrcmp(curr_qos,
									new_qos+1)) {
								break;
							}
						}
						if (!curr_qos) {
							list_append(assoc->qos_list,
									xstrdup(new_qos+1));
						}
						list_iterator_reset(curr_qos_itr);
					}
				}

				list_iterator_destroy(new_qos_itr);
				list_iterator_destroy(curr_qos_itr);
				list_flush(delta_qos_list);
			}

			assoc->parent_id = parent_id;

			//info("parent id is %d", assoc->parent_id);
			//log_assoc_rec(assoc);
		}
	} else {
		int count_tmp = KCIResultGetRowCount(result);
		for(int i = 0; i < count_tmp; i++) {
			slurmdb_assoc_rec_t *assoc =xmalloc(sizeof(slurmdb_assoc_rec_t));
			KCIResult *result2 = NULL;
			char *tmp = NULL;
			uint16_t deleted = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_DELETED));
			list_append(assoc_list, assoc);
			assoc->id = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_ID));
			assoc->is_def = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_DEFAULT));

			if (deleted)
				assoc->flags |= ASSOC_FLAG_DELETED;

			assoc->lft = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_LFT));
			assoc->rgt = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_RGT));

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_USER);
			if (*tmp !='\0')
				assoc->user = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_USER));
			assoc->acct = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_ACCT));
			assoc->cluster = xstrdup(cluster_name);

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GJ);
			if ( *tmp != '\0')
				assoc->grp_jobs = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_GJ));
			else
				assoc->grp_jobs = INFINITE;

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GJA);
			if (*tmp != '\0')
				assoc->grp_jobs_accrue =
					slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_GJA));
			else
				assoc->grp_jobs_accrue = INFINITE;
			
			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GSJ);
			if (*tmp != '\0')
				assoc->grp_submit_jobs =
					slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_GSJ));
			else
				assoc->grp_submit_jobs = INFINITE;
			
			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GW);
			if (*tmp != '\0')
				assoc->grp_wall = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_GW));
			else
				assoc->grp_wall = INFINITE;

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GT);
			if (*tmp != '\0')
				assoc->grp_tres = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_GT));
			
			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GTM);
			if (*tmp != '\0')
				assoc->grp_tres_mins = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_GTM));
			
			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GTRM);
			if (*tmp != '\0')
				assoc->grp_tres_run_mins = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_GTRM));

			parent_acct = KCIResultGetColumnValue(result, i, ASSOC_REQ_ACCT);

			tmp =KCIResultGetColumnValue(result, i, ASSOC_REQ_PARENT);
			if (!without_parent_info
				&& (*tmp != '\0') ) {
				assoc->parent_acct = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_PARENT));
				parent_acct = KCIResultGetColumnValue(result, i, ASSOC_REQ_PARENT);
			} else if (!assoc->user) {
				/* This is the root association so we have no
				parent id */
				parent_acct = NULL;
				parent_id = 0;
			}

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_PART);
			if (*tmp != '\0')
				assoc->partition = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_PART));

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_FS);
			if (*tmp != '\0')
				assoc->shares_raw = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_FS));
			else
				assoc->shares_raw = 1;

			if (!without_parent_info && parent_acct &&
				(!last_acct || !last_cluster
				|| xstrcmp(parent_acct, last_acct)
				|| xstrcmp(cluster_name, last_cluster))) {
				/*
				query = xstrdup_printf(
					"exec get_parent_limits('%s', "
					"'%s', '%s', %u); %s",
					assoc_table, parent_acct,
					cluster_name,
					without_parent_limits,
					get_parent_limits_select);
				debug4("%d(%s:%d) query\n%s",
					kingbase_conn->conn, THIS_FILE, __LINE__, query);
				//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);	   
				result2 = kingbase_db_query_ret(kingbase_conn, query, 1);
				if (KCIResultGetStatusCode(result2) != EXECUTE_TUPLES_OK) {
					xfree(query);
					break;
				}
				*/
				//xfree(query);
				int tmp_count=_get_parend(result2, parent_acct,query,cluster_name ,assoc_table, kingbase_conn, with_assoc_sql, 0);
	//next: 
				if (tmp_count <= 0) {
					parent_id = 0;
					goto no_parent_limits;
				}
				parent_id = slurm_atoul(with_assoc_sql[ASSOC2_REQ_PARENT_ID]);
				if (!without_parent_limits) {
					if ((with_assoc_sql[ASSOC2_REQ_DEF_QOS] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_DEF_QOS])))
						parent_def_qos_id = slurm_atoul(
							with_assoc_sql[ASSOC2_REQ_DEF_QOS]);
					else
						parent_def_qos_id = 0;

					if ((with_assoc_sql[ASSOC2_REQ_MJ] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MJ])))
						parent_mj = slurm_atoul(
							with_assoc_sql[ASSOC2_REQ_MJ]);
					else
						parent_mj = INFINITE;

					if ((with_assoc_sql[ASSOC2_REQ_MJA] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MJA])))
						parent_mja = slurm_atoul(
							with_assoc_sql[ASSOC2_REQ_MJA]);
					else
						parent_mja = INFINITE;

					if ((with_assoc_sql[ASSOC2_REQ_MPT]  != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MPT])))
						parent_mpt = slurm_atoul(
							with_assoc_sql[ASSOC2_REQ_MPT]);
					else
						parent_mpt = INFINITE;

					if ((with_assoc_sql[ASSOC2_REQ_MSJ] != NULL) && (strlen(with_assoc_sql[ ASSOC2_REQ_MSJ])))
						parent_msj = slurm_atoul(
							with_assoc_sql[ASSOC2_REQ_MSJ]);
					else
						parent_msj = INFINITE;

					if ((with_assoc_sql[ASSOC2_REQ_MWPJ] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MWPJ])))
						parent_mwpj = slurm_atoul(
							with_assoc_sql[ASSOC2_REQ_MWPJ]);
					else
						parent_mwpj = INFINITE;


					if ((with_assoc_sql[ASSOC2_REQ_PRIO] != NULL) &&  (strlen(with_assoc_sql[ASSOC2_REQ_PRIO])))
						parent_prio = slurm_atoul(
							with_assoc_sql[ASSOC2_REQ_PRIO]);
					else
						parent_prio = INFINITE;

					xfree(parent_mtpj);
					if ((with_assoc_sql[ASSOC2_REQ_MTPJ] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MTPJ])))
						parent_mtpj = xstrdup(
							with_assoc_sql[ASSOC2_REQ_MTPJ]);

					xfree(parent_mtpn);
					if ((with_assoc_sql[ASSOC2_REQ_MTPN]!= NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MTPN])))
						parent_mtpn = xstrdup(
							with_assoc_sql[ASSOC2_REQ_MTPN]);

					xfree(parent_mtmpj);
					if ((with_assoc_sql[ASSOC2_REQ_MTMPJ]!= NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MTMPJ])))
						parent_mtmpj = xstrdup(
							with_assoc_sql[ASSOC2_REQ_MTMPJ]);

					xfree(parent_mtrm);
					if ((with_assoc_sql[ASSOC2_REQ_MTRM]!= NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MTRM])))
						parent_mtrm = xstrdup(
							with_assoc_sql[ASSOC2_REQ_MTRM]);

					xfree(parent_qos);
					if ((with_assoc_sql[ASSOC2_REQ_QOS]!= NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_QOS])))
						parent_qos =
							xstrdup(with_assoc_sql[ASSOC2_REQ_QOS]);

					xfree(parent_delta_qos);
					if ((with_assoc_sql[ASSOC2_REQ_DELTA_QOS] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_DELTA_QOS])))
						parent_delta_qos = xstrdup(
							with_assoc_sql[ASSOC2_REQ_DELTA_QOS]);
					
				}
				last_acct = parent_acct;
				last_cluster = cluster_name;
			no_parent_limits:
				for(int i =0 ; i < 14; i++) {
					if(with_assoc_sql[i])
					xfree(with_assoc_sql[i]);
				}
				if(result2)
					KCIResultDealloc(result2);
			}
			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_DEF_QOS);
			if (*tmp != '\0')
				assoc->def_qos_id = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_DEF_QOS));
			else
				assoc->def_qos_id = parent_def_qos_id;

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MJ);
			if (*tmp != '\0')
				assoc->max_jobs = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_MJ));
			else
				assoc->max_jobs = parent_mj;

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MJA);
			if (*tmp != '\0')
				assoc->max_jobs_accrue =
					slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_MJA));
			else
				assoc->max_jobs_accrue = parent_mja;
			
			tmp= KCIResultGetColumnValue(result, i, ASSOC_REQ_MPT);
			if (*tmp != '\0')
				assoc->min_prio_thresh = slurm_atoul(
					KCIResultGetColumnValue(result, i, ASSOC_REQ_MPT));
			else
				assoc->min_prio_thresh = parent_mpt;

			tmp =KCIResultGetColumnValue(result, i, ASSOC_REQ_MSJ);
			if (*tmp != '\0')
				assoc->max_submit_jobs = slurm_atoul(
					KCIResultGetColumnValue(result, i, ASSOC_REQ_MSJ));
			else
				assoc->max_submit_jobs = parent_msj;

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MWPJ);
			if (*tmp != '\0')
				assoc->max_wall_pj = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_MWPJ));
			else
				assoc->max_wall_pj = parent_mwpj;

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_PRIO);
			if (*tmp != '\0')
				assoc->priority = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_PRIO));
			else
				assoc->priority = parent_prio;
			
			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MTPJ);
			if (*tmp != '\0')
				assoc->max_tres_pj = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_MTPJ));

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MTPN);
			if (*tmp != '\0')
				assoc->max_tres_pn = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_MTPN));

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MTMPJ);
			if (*tmp != '\0')
				assoc->max_tres_mins_pj = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_MTMPJ));

			tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MTRM);
			if (*tmp != '\0')
				assoc->max_tres_run_mins = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_MTRM));

			/* For the tres limits we just concatted the limits going up
			* the hierarchy slurmdb_tres_list_from_string will just skip
			* over any reoccuring limit to give us the first one per
			* TRES.
			*/
			slurmdb_combine_tres_strings(
				&assoc->max_tres_pj, parent_mtpj,
				TRES_STR_FLAG_SORT_ID);
			slurmdb_combine_tres_strings(
				&assoc->max_tres_pn, parent_mtpn,
				TRES_STR_FLAG_SORT_ID);
			slurmdb_combine_tres_strings(
				&assoc->max_tres_mins_pj, parent_mtmpj,
				TRES_STR_FLAG_SORT_ID);
			slurmdb_combine_tres_strings(
				&assoc->max_tres_run_mins, parent_mtrm,
				TRES_STR_FLAG_SORT_ID);

			assoc->qos_list = list_create(xfree_ptr);

			/* do a plus 1 since a comma is the first thing there
			* in the list.  Also you can never have both a qos
			* and a delta qos so if you have a qos don't worry
			* about the delta.
			*/
			tmp = KCIResultGetColumnValue(result, i,ASSOC_REQ_QOS);
			debug("KCIResultGetColumnValue(result, i,ASSOC_REQ_QOS)[%d]=%s",i,KCIResultGetColumnValue(result, i,ASSOC_REQ_QOS));
			if (*tmp != '\0')
				slurm_addto_char_list(assoc->qos_list,
							KCIResultGetColumnValue(result, i,ASSOC_REQ_QOS)+1);
			else {
				/* if qos is set on the association itself do
				not worry about the deltas
				*/

				/* add the parents first */
				if (parent_qos)
					slurm_addto_char_list(assoc->qos_list,
								parent_qos+1);

				/* then add the parents delta */
				if (parent_delta_qos)
					slurm_addto_char_list(delta_qos_list,
								parent_delta_qos+1);

				/* now add the associations */ 
				tmp = KCIResultGetColumnValue(result, i,ASSOC_REQ_DELTA_QOS);
				
				if (*tmp != '\0')
					slurm_addto_char_list(
						delta_qos_list,
						KCIResultGetColumnValue(result, i,ASSOC_REQ_DELTA_QOS)+1);
			}

			/* Sometimes we want to see exactly what is here in
			the database instead of a complete list.  This will
			give it to us.
			*/
			if (with_raw_qos && list_count(delta_qos_list)) {
				list_transfer(assoc->qos_list, delta_qos_list);
				list_flush(delta_qos_list);
			} else if (list_count(delta_qos_list)) {
				ListIterator curr_qos_itr =
					list_iterator_create(assoc->qos_list);
				ListIterator new_qos_itr =
					list_iterator_create(delta_qos_list);
				char *new_qos = NULL, *curr_qos = NULL;

				while ((new_qos = list_next(new_qos_itr))) {
					if (new_qos[0] == '-') {
						while ((curr_qos =
							list_next(curr_qos_itr))) {
							if (!xstrcmp(curr_qos,
									new_qos+1)) {
								list_delete_item(
									curr_qos_itr);
								break;
							}
						}
						list_iterator_reset(curr_qos_itr);
					} else if (new_qos[0] == '+') {
						while ((curr_qos =
							list_next(curr_qos_itr))) {
							if (!xstrcmp(curr_qos,
									new_qos+1)) {
								break;
							}
						}
						if (!curr_qos) {
							list_append(assoc->qos_list,
									xstrdup(new_qos+1));
						}
						list_iterator_reset(curr_qos_itr);
					}
				}

				list_iterator_destroy(new_qos_itr);
				list_iterator_destroy(curr_qos_itr);
				list_flush(delta_qos_list);
			}

			assoc->parent_id = parent_id;

			//info("parent id is %d", assoc->parent_id);
			//log_assoc_rec(assoc);
		}
	}
#else
	int count_tmp = KCIResultGetRowCount(result);
	for(int i = 0; i < count_tmp; i++) {
		slurmdb_assoc_rec_t *assoc =xmalloc(sizeof(slurmdb_assoc_rec_t));
		KCIResult *result2 = NULL;
		char *tmp = NULL;
		uint16_t deleted = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_DELETED));
		list_append(assoc_list, assoc);
		assoc->id = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_ID));
		assoc->is_def = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_DEFAULT));

		if (deleted)
			assoc->flags |= ASSOC_FLAG_DELETED;

		assoc->lft = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_LFT));
		assoc->rgt = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_RGT));

		tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_USER);
		if (*tmp !='\0')
			assoc->user = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_USER));
		assoc->acct = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_ACCT));
		assoc->cluster = xstrdup(cluster_name);

        tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GJ);
		if ( *tmp != '\0')
			assoc->grp_jobs = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_GJ));
		else
			assoc->grp_jobs = INFINITE;

        tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GJA);
		if (*tmp != '\0')
			assoc->grp_jobs_accrue =
				slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_GJA));
		else
			assoc->grp_jobs_accrue = INFINITE;
		
		tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GSJ);
		if (*tmp != '\0')
			assoc->grp_submit_jobs =
				slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_GSJ));
		else
			assoc->grp_submit_jobs = INFINITE;
        
		tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GW);
		if (*tmp != '\0')
			assoc->grp_wall = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_GW));
		else
			assoc->grp_wall = INFINITE;

		tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GT);
		if (*tmp != '\0')
			assoc->grp_tres = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_GT));
		
		tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GTM);
		if (*tmp != '\0')
			assoc->grp_tres_mins = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_GTM));
		
		tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_GTRM);
		if (*tmp != '\0')
			assoc->grp_tres_run_mins = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_GTRM));

		parent_acct = KCIResultGetColumnValue(result, i, ASSOC_REQ_ACCT);

        tmp =KCIResultGetColumnValue(result, i, ASSOC_REQ_PARENT);
		if (!without_parent_info
		    && (*tmp != '\0') ) {
			assoc->parent_acct = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_PARENT));
			parent_acct = KCIResultGetColumnValue(result, i, ASSOC_REQ_PARENT);
		} else if (!assoc->user) {
			/* This is the root association so we have no
			   parent id */
			parent_acct = NULL;
			parent_id = 0;
		}

        tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_PART);
		if (*tmp != '\0')
			assoc->partition = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_PART));

	    tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_FS);
		if (*tmp != '\0')
			assoc->shares_raw = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_FS));
		else
			assoc->shares_raw = 1;

		if (!without_parent_info && parent_acct &&
		    (!last_acct || !last_cluster
		     || xstrcmp(parent_acct, last_acct)
		     || xstrcmp(cluster_name, last_cluster))) {
			/*
			query = xstrdup_printf(
				"exec get_parent_limits('%s', "
				"'%s', '%s', %u); %s",
				assoc_table, parent_acct,
				cluster_name,
				without_parent_limits,
				get_parent_limits_select);
			debug4("%d(%s:%d) query\n%s",
			       kingbase_conn->conn, THIS_FILE, __LINE__, query);
			//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);	   
			result2 = kingbase_db_query_ret(kingbase_conn, query, 1);
			if (KCIResultGetStatusCode(result2) != EXECUTE_TUPLES_OK) {
				xfree(query);
				break;
			}
			*/
			//xfree(query);
			int tmp_count=_get_parend(result2, parent_acct,query,cluster_name ,assoc_table, kingbase_conn, with_assoc_sql, 0);
//next: 
			if (tmp_count <= 0) {
				parent_id = 0;
				goto no_parent_limits;
			}
			parent_id = slurm_atoul(with_assoc_sql[ASSOC2_REQ_PARENT_ID]);
			if (!without_parent_limits) {
				if ((with_assoc_sql[ASSOC2_REQ_DEF_QOS] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_DEF_QOS])))
					parent_def_qos_id = slurm_atoul(
						with_assoc_sql[ASSOC2_REQ_DEF_QOS]);
				else
					parent_def_qos_id = 0;

				if ((with_assoc_sql[ASSOC2_REQ_MJ] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MJ])))
					parent_mj = slurm_atoul(
						with_assoc_sql[ASSOC2_REQ_MJ]);
				else
					parent_mj = INFINITE;

				if ((with_assoc_sql[ASSOC2_REQ_MJA] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MJA])))
					parent_mja = slurm_atoul(
						with_assoc_sql[ASSOC2_REQ_MJA]);
				else
					parent_mja = INFINITE;

				if ((with_assoc_sql[ASSOC2_REQ_MPT]  != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MPT])))
					parent_mpt = slurm_atoul(
						with_assoc_sql[ASSOC2_REQ_MPT]);
				else
					parent_mpt = INFINITE;

				if ((with_assoc_sql[ASSOC2_REQ_MSJ] != NULL) && (strlen(with_assoc_sql[ ASSOC2_REQ_MSJ])))
					parent_msj = slurm_atoul(
						with_assoc_sql[ASSOC2_REQ_MSJ]);
				else
					parent_msj = INFINITE;

				if ((with_assoc_sql[ASSOC2_REQ_MWPJ] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MWPJ])))
					parent_mwpj = slurm_atoul(
						with_assoc_sql[ASSOC2_REQ_MWPJ]);
				else
					parent_mwpj = INFINITE;


				if ((with_assoc_sql[ASSOC2_REQ_PRIO] != NULL) &&  (strlen(with_assoc_sql[ASSOC2_REQ_PRIO])))
					parent_prio = slurm_atoul(
						with_assoc_sql[ASSOC2_REQ_PRIO]);
				else
					parent_prio = INFINITE;

				xfree(parent_mtpj);
				if ((with_assoc_sql[ASSOC2_REQ_MTPJ] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MTPJ])))
					parent_mtpj = xstrdup(
						with_assoc_sql[ASSOC2_REQ_MTPJ]);

				xfree(parent_mtpn);
				if ((with_assoc_sql[ASSOC2_REQ_MTPN]!= NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MTPN])))
					parent_mtpn = xstrdup(
						with_assoc_sql[ASSOC2_REQ_MTPN]);

				xfree(parent_mtmpj);
				if ((with_assoc_sql[ASSOC2_REQ_MTMPJ]!= NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MTMPJ])))
					parent_mtmpj = xstrdup(
						with_assoc_sql[ASSOC2_REQ_MTMPJ]);

				xfree(parent_mtrm);
				if ((with_assoc_sql[ASSOC2_REQ_MTRM]!= NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_MTRM])))
					parent_mtrm = xstrdup(
						with_assoc_sql[ASSOC2_REQ_MTRM]);

				xfree(parent_qos);
				if ((with_assoc_sql[ASSOC2_REQ_QOS]!= NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_QOS])))
					parent_qos =
						xstrdup(with_assoc_sql[ASSOC2_REQ_QOS]);

				xfree(parent_delta_qos);
				if ((with_assoc_sql[ASSOC2_REQ_DELTA_QOS] != NULL) && (strlen(with_assoc_sql[ASSOC2_REQ_DELTA_QOS])))
					parent_delta_qos = xstrdup(
						with_assoc_sql[ASSOC2_REQ_DELTA_QOS]);
				
			}
			last_acct = parent_acct;
			last_cluster = cluster_name;
		no_parent_limits:
			for(int i =0 ; i < 14; i++) {
				if(with_assoc_sql[i])
				xfree(with_assoc_sql[i]);
			}
			if(result2)
				KCIResultDealloc(result2);
		}
        tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_DEF_QOS);
		if (*tmp != '\0')
			assoc->def_qos_id = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_DEF_QOS));
		else
			assoc->def_qos_id = parent_def_qos_id;

        tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MJ);
		if (*tmp != '\0')
			assoc->max_jobs = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_MJ));
		else
			assoc->max_jobs = parent_mj;

        tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MJA);
		if (*tmp != '\0')
			assoc->max_jobs_accrue =
				slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_MJA));
		else
			assoc->max_jobs_accrue = parent_mja;
         
		tmp= KCIResultGetColumnValue(result, i, ASSOC_REQ_MPT);
		if (*tmp != '\0')
			assoc->min_prio_thresh = slurm_atoul(
				KCIResultGetColumnValue(result, i, ASSOC_REQ_MPT));
		else
			assoc->min_prio_thresh = parent_mpt;

        tmp =KCIResultGetColumnValue(result, i, ASSOC_REQ_MSJ);
		if (*tmp != '\0')
			assoc->max_submit_jobs = slurm_atoul(
				KCIResultGetColumnValue(result, i, ASSOC_REQ_MSJ));
		else
			assoc->max_submit_jobs = parent_msj;

		tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MWPJ);
		if (*tmp != '\0')
			assoc->max_wall_pj = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_MWPJ));
		else
			assoc->max_wall_pj = parent_mwpj;

        tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_PRIO);
		if (*tmp != '\0')
			assoc->priority = slurm_atoul(KCIResultGetColumnValue(result, i, ASSOC_REQ_PRIO));
		else
			assoc->priority = parent_prio;
        
		tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MTPJ);
		if (*tmp != '\0')
			assoc->max_tres_pj = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_MTPJ));

		tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MTPN);
		if (*tmp != '\0')
			assoc->max_tres_pn = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_MTPN));

        tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MTMPJ);
		if (*tmp != '\0')
			assoc->max_tres_mins_pj = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_MTMPJ));

		 tmp = KCIResultGetColumnValue(result, i, ASSOC_REQ_MTRM);
		if (*tmp != '\0')
			assoc->max_tres_run_mins = xstrdup(KCIResultGetColumnValue(result, i, ASSOC_REQ_MTRM));

		/* For the tres limits we just concatted the limits going up
		 * the hierarchy slurmdb_tres_list_from_string will just skip
		 * over any reoccuring limit to give us the first one per
		 * TRES.
		 */
		slurmdb_combine_tres_strings(
			&assoc->max_tres_pj, parent_mtpj,
			TRES_STR_FLAG_SORT_ID);
		slurmdb_combine_tres_strings(
			&assoc->max_tres_pn, parent_mtpn,
			TRES_STR_FLAG_SORT_ID);
		slurmdb_combine_tres_strings(
			&assoc->max_tres_mins_pj, parent_mtmpj,
			TRES_STR_FLAG_SORT_ID);
		slurmdb_combine_tres_strings(
			&assoc->max_tres_run_mins, parent_mtrm,
			TRES_STR_FLAG_SORT_ID);

		assoc->qos_list = list_create(xfree_ptr);

		/* do a plus 1 since a comma is the first thing there
		 * in the list.  Also you can never have both a qos
		 * and a delta qos so if you have a qos don't worry
		 * about the delta.
		 */
		tmp = KCIResultGetColumnValue(result, i,ASSOC_REQ_QOS);
		debug("KCIResultGetColumnValue(result, i,ASSOC_REQ_QOS)[%d]=%s",i,KCIResultGetColumnValue(result, i,ASSOC_REQ_QOS));
		if (*tmp != '\0')
			slurm_addto_char_list(assoc->qos_list,
					      KCIResultGetColumnValue(result, i,ASSOC_REQ_QOS)+1);
		else {
			/* if qos is set on the association itself do
			   not worry about the deltas
			*/

			/* add the parents first */
			if (parent_qos)
				slurm_addto_char_list(assoc->qos_list,
						      parent_qos+1);

			/* then add the parents delta */
			if (parent_delta_qos)
				slurm_addto_char_list(delta_qos_list,
						      parent_delta_qos+1);

			/* now add the associations */ 
			tmp = KCIResultGetColumnValue(result, i,ASSOC_REQ_DELTA_QOS);
			
			if (*tmp != '\0')
				slurm_addto_char_list(
					delta_qos_list,
					KCIResultGetColumnValue(result, i,ASSOC_REQ_DELTA_QOS)+1);
		}

		/* Sometimes we want to see exactly what is here in
		   the database instead of a complete list.  This will
		   give it to us.
		*/
		if (with_raw_qos && list_count(delta_qos_list)) {
			list_transfer(assoc->qos_list, delta_qos_list);
			list_flush(delta_qos_list);
		} else if (list_count(delta_qos_list)) {
			ListIterator curr_qos_itr =
				list_iterator_create(assoc->qos_list);
			ListIterator new_qos_itr =
				list_iterator_create(delta_qos_list);
			char *new_qos = NULL, *curr_qos = NULL;

			while ((new_qos = list_next(new_qos_itr))) {
				if (new_qos[0] == '-') {
					while ((curr_qos =
						list_next(curr_qos_itr))) {
						if (!xstrcmp(curr_qos,
							     new_qos+1)) {
							list_delete_item(
								curr_qos_itr);
							break;
						}
					}
					list_iterator_reset(curr_qos_itr);
				} else if (new_qos[0] == '+') {
					while ((curr_qos =
						list_next(curr_qos_itr))) {
						if (!xstrcmp(curr_qos,
							     new_qos+1)) {
							break;
						}
					}
					if (!curr_qos) {
						list_append(assoc->qos_list,
							    xstrdup(new_qos+1));
					}
					list_iterator_reset(curr_qos_itr);
				}
			}

			list_iterator_destroy(new_qos_itr);
			list_iterator_destroy(curr_qos_itr);
			list_flush(delta_qos_list);
		}

		assoc->parent_id = parent_id;

		//info("parent id is %d", assoc->parent_id);
		//log_assoc_rec(assoc);
	}
#endif
	xfree(parent_mtpj);
	xfree(parent_mtpn);
	xfree(parent_mtmpj);
	xfree(parent_mtrm);
	KCIResultDealloc(result);

	FREE_NULL_LIST(delta_qos_list);

	xfree(parent_delta_qos);
	xfree(parent_qos);

	if (with_usage && assoc_list && list_count(assoc_list))
		get_usage_for_list(kingbase_conn, DBD_GET_ASSOC_USAGE,
				   assoc_list, cluster_name,
				   assoc_cond->usage_start,
				   assoc_cond->usage_end);

	list_transfer(sent_list, assoc_list);
	FREE_NULL_LIST(assoc_list);
	return SLURM_SUCCESS;
}

extern int as_kingbase_get_modified_lfts(kingbase_conn_t *kingbase_conn,
				      char *cluster_name, uint32_t start_lft)
{
	KCIResult *result = NULL;
	char *query = xstrdup_printf(
		"select id_assoc, lft from `%s_%s` where lft > %u "
		"and deleted = 0",
		cluster_name, assoc_table, start_lft);
	DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", query);
	//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);
	result = kingbase_db_query_ret(kingbase_conn, query, 0);
	if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK) {
		KCIResultDealloc(result);
		xfree(query);
		error("couldn't query the database for modified lfts");
		return SLURM_ERROR;
	}
	xfree(query);	
	for(int i = 0; i < KCIResultGetRowCount(result); i++){
		slurmdb_assoc_rec_t *assoc =
			xmalloc(sizeof(slurmdb_assoc_rec_t));
		slurmdb_init_assoc_rec(assoc, 0);
		assoc->id = slurm_atoul(KCIResultGetColumnValue(result, i, 0));
		assoc->lft = slurm_atoul(KCIResultGetColumnValue(result, i, 1));
		assoc->cluster = xstrdup(cluster_name);
		if (addto_update_list(kingbase_conn->update_list,
				      SLURMDB_MODIFY_ASSOC,
				      assoc) != SLURM_SUCCESS)
			slurmdb_destroy_assoc_rec(assoc);
	}
	KCIResultDealloc(result);

	return SLURM_SUCCESS;
}

extern int as_kingbase_add_assocs(kingbase_conn_t *kingbase_conn, uint32_t uid,
			       List assoc_list)
{
	ListIterator itr = NULL;
	int rc = SLURM_SUCCESS;
	int i=0;
	slurmdb_assoc_rec_t *object = NULL;
	char *cols = NULL, *vals = NULL, *txn_query = NULL;
	char *extra = NULL, *query = NULL, *update = NULL, *tmp_extra = NULL;
	char *parent = NULL;
	time_t now = time(NULL);
	char *user_name = NULL;
	char *tmp_char = NULL;
	int assoc_id = 0;
#ifdef __METASTACK_OPT_SACCTMGR_ADD_USER
	int incr = 0, my_par_id = 0, my_right = 0;
#else
	int incr = 0, my_left = 0, my_par_id = 0;
#endif
	int moved_parent = 0;
	KCIResult *result = NULL;

	char *old_parent = NULL, *old_cluster = NULL;
	char *last_parent = NULL, *last_cluster = NULL;
	List local_cluster_list = NULL;
	List added_user_list = NULL;
	bool is_coord = false;
	slurmdb_update_object_t *update_object = NULL;
	List assoc_list_tmp = NULL;
	bool acct_added = false;

	if (!assoc_list) {
		error("No association list given");
		return SLURM_ERROR;
	}

	if (check_connection(kingbase_conn) != SLURM_SUCCESS)
		return ESLURM_DB_CONNECTION;

	if (!is_user_min_admin_level(kingbase_conn, uid,
				     SLURMDB_ADMIN_OPERATOR)) {
		ListIterator itr2 = NULL;
		slurmdb_user_rec_t user;
		slurmdb_coord_rec_t *coord = NULL;
		slurmdb_assoc_rec_t *object = NULL;

		memset(&user, 0, sizeof(slurmdb_user_rec_t));
		user.uid = uid;

		if (!is_user_any_coord(kingbase_conn, &user)) {
			error("Only admins/operators/coordinators "
			      "can add associations");
			return ESLURM_ACCESS_DENIED;
		}

		itr = list_iterator_create(assoc_list);
		itr2 = list_iterator_create(user.coord_accts);
		while ((object = list_next(itr))) {
			char *account = "root";
			if (object->user)
				account = object->acct;
			else if (object->parent_acct)
				account = object->parent_acct;
			list_iterator_reset(itr2);
			while ((coord = list_next(itr2))) {
				if (!xstrcasecmp(coord->name, account))
					break;
			}
			if (!coord)
				break;
		}
		list_iterator_destroy(itr2);
		list_iterator_destroy(itr);
		if (!coord)  {
			error("Coordinator %s(%d) tried to add associations "
			      "where they were not allowed",
			      user.name, user.uid);
			return ESLURM_ACCESS_DENIED;
		}
		is_coord = true;
	}

	local_cluster_list = list_create(NULL);
	user_name = uid_to_string((uid_t) uid);
	/* these need to be in a specific order */
	list_sort(assoc_list, (ListCmpF)_assoc_sort_cluster);

#ifdef __METASTACK_OPT_SACCTMGR_ADD_USER
	slurm_mutex_lock(&assoc_lock);
#endif

	itr = list_iterator_create(assoc_list);
	while ((object = list_next(itr))) {
		if (!object->cluster || !object->cluster[0]
		    || !object->acct || !object->acct[0]) {
			error("We need a association cluster and "
			      "acct to add one.");
			rc = SLURM_ERROR;
			continue;
		}

		/*
		 * If the user issuing the command is a coordinator,
		 * do not allow changing the default account
		 */
		if (is_coord && (object->is_def == 1)) {
			char *query = NULL;
			int has_def_acct = 0;
			/* Check if there is already a default account. */
			xstrfmtcat(query, "select id_assoc from `%s_%s` "
				   "where `user`='%s' and acct!='%s' and is_def=1 "
				   "and deleted=0;",
				   object->cluster, assoc_table,
				   object->user, object->acct);
			DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s",
			         query);
			//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);	
			result = kingbase_db_query_ret(kingbase_conn, query, 1);	 
			if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK) {
				KCIResultDealloc(result);
				xfree(query);
				rc = SLURM_ERROR;
				break;
			}

			xfree(query);
			has_def_acct = KCIResultGetRowCount(result);
			KCIResultDealloc(result);

			if (has_def_acct) {
				debug("Coordinator %s(%d) tried to change the default account of user %s to account %s.  This is only allowed on initial user creation. Ignoring default account.",
				      user_name, uid, object->user,
				      object->acct);
				object->is_def = 0;
			}
		}

		if (is_coord && _check_coord_qos(kingbase_conn, object->cluster,
						 object->acct, user_name,
						 object->qos_list)
		    == SLURM_ERROR) {
			assoc_mgr_lock_t locks = {
				NO_LOCK, NO_LOCK, READ_LOCK, NO_LOCK,
				NO_LOCK, NO_LOCK, NO_LOCK };
			char *requested_qos;

			assoc_mgr_lock(&locks);
			requested_qos = get_qos_complete_str(
				assoc_mgr_qos_list, object->qos_list);
			assoc_mgr_unlock(&locks);
			error("Coordinator %s(%d) does not have the "
			      "access to all the qos requested (%s), "
			      "so they can't add to account "
			      "%s with it.",
			      user_name, uid, requested_qos,
			      object->acct);
			xfree(requested_qos);
			rc = ESLURM_ACCESS_DENIED;
			break;
		}

		/* When adding if this isn't a default might as well
		   force it to be 0 to avoid confusion since
		   uninitialized it is NO_VAL.
		*/
		if (object->is_def != 1)
			object->is_def = 0;

		if (!list_find_first(local_cluster_list,
				     slurm_find_char_in_list,
				     object->cluster))
			list_append(local_cluster_list, object->cluster);

		if (object->parent_acct) {
			parent = object->parent_acct;
		} else if (object->user) {
			parent = object->acct;
		} else {
			parent = "root";
		}

		xstrcat(cols, "creation_time, mod_time, acct");
		xstrfmtcat(vals, "%ld, %ld, '%s'",
			   now, now, object->acct);
		xstrfmtcat(update, "where acct='%s'", object->acct);

		xstrfmtcat(extra, ", mod_time=%ld, acct='%s'",
			   now, object->acct);
		if (!object->user) {
			acct_added = true;
			xstrcat(cols, ", parent_acct");
			xstrfmtcat(vals, ", '%s'", parent);
			xstrfmtcat(extra, ", parent_acct='%s', `user`=''",
				   parent);
			xstrfmtcat(update, " and `user`=''");
		} else {
			char *part = object->partition;
			xstrcat(cols, ", `user`");
			xstrfmtcat(vals, ", '%s'", object->user);
			xstrfmtcat(update, " and `user`='%s'", object->user);
			xstrfmtcat(extra, ", `user`='%s'", object->user);

			/* We need to give a partition whether it be
			 * '' or the actual partition name given
			 */
			if (!part)
				part = "";
			xstrcat(cols, ", partition");
			xstrfmtcat(vals, ", '%s'", part);
			xstrfmtcat(update, " and partition='%s'", part);
			xstrfmtcat(extra, ", partition='%s'", part);
			if (!added_user_list)
				added_user_list = list_create(NULL);
			if (!list_find_first(added_user_list,
					     slurm_find_char_in_list,
					     object->user))
				list_append(added_user_list, object->user);
		}

		if (object->id) {
			xstrcat(cols, ", id_assoc");
			xstrfmtcat(vals, ", '%u'", object->id);
			xstrfmtcat(update, " and id_assoc='%u'", object->id);
			xstrfmtcat(extra, ", id_assoc='%u'", object->id);
		}

		if ((rc = setup_assoc_limits(object, &cols, &vals, &extra,
					     QOS_LEVEL_NONE, 1))) {
			error("%s: Failed, setup_assoc_limits functions returned error",
			      __func__);
			xfree(query);
			xfree(cols);
			xfree(vals);
			xfree(extra);
			xfree(update);
			break;
		}


		xstrcat(tmp_char, aassoc_req_inx[0]);
		for(i=1; i<AASSOC_COUNT; i++)
			xstrfmtcat(tmp_char, ", %s", aassoc_req_inx[i]);

		xstrfmtcat(query,
			   "select %s from `%s_%s` %s order by lft "
			   "FOR UPDATE;",
			   tmp_char, object->cluster, assoc_table, update);
		xfree(tmp_char);
		DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", query);
		//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);
		result = kingbase_db_query_ret(kingbase_conn, query, 0);
		if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK) {
			KCIResultDealloc(result);
			xfree(query);
			xfree(cols);
			xfree(vals);
			xfree(extra);
			xfree(update);
			error("couldn't query the database");
			rc = SLURM_ERROR;
			break;
		}
		xfree(query);

		assoc_id = 0;

		if (KCIResultGetRowCount(result) == 0) {
			/* This code speeds up the add process quite a bit
			 * here we are only doing an update when we are done
			 * adding to a specific group (cluster/account) other
			 * than that we are adding right behind what we were
			 * so just total them up and then do one update
			 * instead of the slow ones that require an update
			 * every time.  There is a incr check outside of the
			 * loop to catch everything on the last spin of the
			 * while.
			 */
			if (!old_parent || !old_cluster
			    || xstrcasecmp(parent, old_parent)
			    || xstrcasecmp(object->cluster, old_cluster)) {
#ifdef __METASTACK_OPT_SACCTMGR_ADD_USER
				char *sel_query = xstrdup_printf(
					"SELECT rgt FROM `%s_%s` WHERE "
					"acct = '%s' and `user` = '' "
					"order by rgt for update;",
					object->cluster, assoc_table,
					parent);
#else 
				char *sel_query = xstrdup_printf(
					"SELECT lft FROM `%s_%s` WHERE "
					"acct = '%s' and `user` = '' "
					"order by lft;",
					object->cluster, assoc_table,
					parent);
#endif
				KCIResult *sel_result = NULL;

				if (incr) {
#ifdef __METASTACK_OPT_SACCTMGR_ADD_USER
					char *up_query = xstrdup_printf(
						"UPDATE `%s_%s` SET "
						"rgt = rgt+%d "
						"WHERE rgt >= %d and deleted < 2;"
						"UPDATE `%s_%s` SET "
						"lft = lft+%d "
						"WHERE lft > %d "
						"and deleted < 2;"
						"UPDATE `%s_%s` SET "
						"deleted = 0 "
						"WHERE deleted = 2;",
						old_cluster, assoc_table,
						incr, my_right,
						old_cluster, assoc_table,
						incr, my_right,
						old_cluster, assoc_table);
#else
					char *up_query = xstrdup_printf(
						"UPDATE `%s_%s` SET "
						"rgt = rgt+%d "
						"WHERE rgt > %d and deleted < 2;"
						"UPDATE `%s_%s` SET "
						"lft = lft+%d "
						"WHERE lft > %d "
						"and deleted < 2;"
						"UPDATE `%s_%s` SET "
						"deleted = 0 "
						"WHERE deleted = 2;",
						old_cluster, assoc_table,
						incr, my_left,
						old_cluster, assoc_table,
						incr, my_left,
						old_cluster, assoc_table);
#endif
					DB_DEBUG(DB_ASSOC, kingbase_conn->conn,
					         "query\n%s", up_query);
					//info("[query] line %d, %s: query: %s", __LINE__, __func__, up_query);		 
					fetch_flag_t *fetch_flag = NULL;
					fetch_result_t *data_rt = NULL;
					fetch_flag = set_fetch_flag(false, false, false);
					data_rt = xmalloc(sizeof(fetch_result_t));
					rc = kingbase_for_fetch(kingbase_conn, up_query, fetch_flag, data_rt);
					free_res_data(data_rt, fetch_flag);
					xfree(up_query);
					if (rc == SLURM_ERROR) {
						error("Couldn't do update");
						xfree(cols);
						xfree(vals);
						xfree(update);
						xfree(extra);
						xfree(sel_query);
						break;
					}
				}

				DB_DEBUG(DB_ASSOC, kingbase_conn->conn,
				         "query\n%s", sel_query);
				//info("[query] line %d, %s: query: %s", __LINE__, __func__, sel_query);		 
				sel_result = kingbase_db_query_ret(kingbase_conn, sel_query, 0);
				if (KCIResultGetStatusCode(sel_result) != EXECUTE_TUPLES_OK) {
					xfree(cols);
					xfree(vals);
					xfree(update);
					xfree(extra);
					xfree(sel_query);
					rc = SLURM_ERROR;
					KCIResultDealloc(sel_result);
					break;
				}

				if (KCIResultGetRowCount(sel_result) == 0) {
					error("Couldn't get left from "
					      "query\n%s",
					      sel_query);
					KCIResultDealloc(sel_result);
					xfree(cols);
					xfree(vals);
					xfree(update);
					xfree(extra);
					xfree(sel_query);
					rc = SLURM_ERROR;
					break;
				}
				xfree(sel_query);

#ifdef __METASTACK_OPT_SACCTMGR_ADD_USER
				my_right = slurm_atoul(KCIResultGetColumnValue(sel_result, 0, 0));
#else
				my_left = slurm_atoul(KCIResultGetColumnValue(sel_result, 0, 0));
#endif
				KCIResultDealloc(sel_result);
				//info("left is %d", my_left);
				old_parent = parent;
				old_cluster = object->cluster;
				incr = 0;
			}
			incr += 2;
#ifdef __METASTACK_OPT_SACCTMGR_ADD_USER
			xstrfmtcat(query,
				   "insert into `%s_%s` "
				   "(%s, lft, rgt, deleted) "
				   "values (%s, %d, %d, 2);",
				   object->cluster, assoc_table, cols,
				   vals, my_right+(incr-2), my_right+(incr-1));
#else
			xstrfmtcat(query,
				   "insert into `%s_%s` "
				   "(%s, lft, rgt, deleted) "
				   "values (%s, %d, %d, 2);",
				   object->cluster, assoc_table, cols,
				   vals, my_left+(incr-1), my_left+incr);
#endif
		} else if (!slurm_atoul(KCIResultGetColumnValue(result, 0, AASSOC_DELETED))) {
			/* We don't need to do anything here */
			debug("This account %s was added already",
			      object->acct);
			xfree(cols);
			xfree(vals);
			xfree(update);
			KCIResultDealloc(result);
			xfree(extra);
			continue;
		} else {
			uint32_t lft = slurm_atoul(KCIResultGetColumnValue(result, 0, AASSOC_LFT));
			uint32_t rgt = slurm_atoul(KCIResultGetColumnValue(result, 0, AASSOC_RGT));

			/* If it was once deleted we have kept the lft
			 * and rgt's consant while it was deleted and
			 * so we can just unset the deleted flag,
			 * check for the parent and move if needed.
			 */
			assoc_id = slurm_atoul(KCIResultGetColumnValue(result, 0, AASSOC_ID));
			if (object->parent_acct
			    && xstrcasecmp(object->parent_acct,
					   KCIResultGetColumnValue(result, 0, AASSOC_PACCT))) {

				/* We need to move the parent! */
				if (_move_parent(kingbase_conn, uid,
						 &lft, &rgt,
						 object->cluster,
						 KCIResultGetColumnValue(result, 0, AASSOC_ID),
						 KCIResultGetColumnValue(result, 0, AASSOC_PACCT),
						 object->parent_acct, now)
				    == SLURM_ERROR) {
					KCIResultDealloc(result);
					continue;
				}
				moved_parent = 1;
			} else {
				object->lft = lft;
				object->rgt = rgt;
			}

			xstrfmtcat(query,
				   //"update `%s_%s` set deleted=0, "
				   //"id_assoc=nextval(id_assoc)%s %s;",  
				   "update `%s_%s` set deleted=0 "
				   "%s %s;",
				   object->cluster, assoc_table,
				   extra, update);
		}
		KCIResultDealloc(result);

		xfree(cols);
		xfree(vals);
		xfree(update);
		DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", query);
		//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);

		fetch_flag_t *fetch_flag = NULL;
		fetch_result_t *data_rt = NULL;

		// char *query2 = xstrdup(query);
		// char *lastSemicolon = xstrrchr(query2, ';'); 
		// if (lastSemicolon != NULL) {
		// 		*lastSemicolon = ' '; // 将最后一个分号替换为空格
		// }
        // xstrfmtcat(query2," returning id_assoc;" );
        
		fetch_flag = set_fetch_flag(true, false, true);
		data_rt = xmalloc(sizeof(fetch_result_t));
		rc = kingbase_for_fetch(kingbase_conn, query, fetch_flag, data_rt);

		xfree(query);
		//xfree(query2);
		if (rc == SLURM_ERROR) {
			error("Couldn't add assoc");
			xfree(extra);
			free_res_data(data_rt, fetch_flag);
			break;	
		}
			
		/* see if this was an insert or update.  On an update
		 * the assoc_id will already be set
		 */
		if (!assoc_id) {
			//(void) last_affected_rows(res);
			assoc_id = data_rt->insert_ret_id;
			//info("last id was %d", assoc_id);
		}
		free_res_data(data_rt, fetch_flag);	
		object->id = assoc_id;

		/* get the parent id only if we haven't moved the
		 * parent since we get the total list if that has
		 * happened */
		if (!moved_parent &&
		    (!last_parent || !last_cluster
		     || xstrcmp(parent, last_parent)
		     || xstrcmp(object->cluster, last_cluster))) {
			uint32_t tmp32 = 0;
			if ((tmp32 = _get_parent_id(kingbase_conn,
						    parent,
						    object->cluster))) {
				my_par_id = tmp32;

				last_parent = parent;
				last_cluster = object->cluster;
			}
		}
		object->parent_id = my_par_id;

		if (!moved_parent) {
			_set_assoc_limits_for_add(kingbase_conn, object);
			if (object->lft == NO_VAL)
				_set_assoc_lft_rgt(kingbase_conn, object);
		}

		if (addto_update_list(kingbase_conn->update_list,
				      SLURMDB_ADD_ASSOC,
				      object) == SLURM_SUCCESS) {
			list_remove(itr);
		}

		/* We don't want to record the transactions of the
		 * tmp_cluster.
		 */

		if (xstrcmp(object->cluster, tmp_cluster_name)) {
			/* we always have a ', ' as the first 2 chars */
			tmp_extra = slurm_add_slash_to_quotes2(extra+2);
			if (txn_query)
				xstrfmtcat(txn_query,
					   ", (%ld, %d, 'id_assoc=%d', "
					   "'%s', '%s', '%s')",
					   now, DBD_ADD_ASSOCS, assoc_id,
					   user_name,
					   tmp_extra, object->cluster);
			else
				xstrfmtcat(txn_query,
					   "insert into %s "
					   "(timestamp, action, name, actor, "
					   "info, cluster) values (%ld, %d, "
					   "'id_assoc=%d', '%s', '%s', '%s')",
					   txn_table,
					   now, DBD_ADD_ASSOCS, assoc_id,
					   user_name,
					   tmp_extra, object->cluster);
			xfree(tmp_extra);
		}
		xfree(extra);
	}
	list_iterator_destroy(itr);
	xfree(user_name);



#ifdef __METASTACK_OPT_SACCTMGR_ADD_USER
	if (rc != SLURM_SUCCESS){
		slurm_mutex_unlock(&assoc_lock);
		goto end_it;
	}
#else
	if (rc != SLURM_SUCCESS)
		goto end_it;
#endif

	if (incr) {
#ifdef __METASTACK_OPT_SACCTMGR_ADD_USER
		char *up_query = xstrdup_printf(
			"UPDATE `%s_%s` SET rgt = rgt+%d "
			"WHERE rgt >= %d and deleted < 2;"
			"UPDATE `%s_%s` SET lft = lft+%d "
			"WHERE lft > %d "
			"and deleted < 2;"
			"UPDATE `%s_%s` SET deleted = 0 "
			"WHERE deleted = 2;",
			old_cluster, assoc_table, incr,
			my_right,
			old_cluster, assoc_table, incr,
			my_right,
			old_cluster, assoc_table);
#else
		char *up_query = xstrdup_printf(
			"UPDATE `%s_%s` SET rgt = rgt+%d "
			"WHERE rgt > %d and deleted < 2;"
			"UPDATE `%s_%s` SET lft = lft+%d "
			"WHERE lft > %d "
			"and deleted < 2;"
			"UPDATE `%s_%s` SET deleted = 0 "
			"WHERE deleted = 2;",
			old_cluster, assoc_table, incr,
			my_left,
			old_cluster, assoc_table, incr,
			my_left,
			old_cluster, assoc_table);
#endif
		DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", up_query);
		//info("[query] line %d, %s: query: %s", __LINE__, __func__, up_query);
		fetch_flag_t *fetch_flag = NULL;
		fetch_result_t *data_rt = NULL;
		fetch_flag = set_fetch_flag(false, false, false);
		data_rt = xmalloc(sizeof(fetch_result_t));
		rc = kingbase_for_fetch(kingbase_conn, up_query, fetch_flag, data_rt);
		free_res_data(data_rt, fetch_flag);	


		xfree(up_query);
		if (rc != SLURM_SUCCESS) {
			error("Couldn't do update 2");
		}
	}

#ifdef __METASTACK_OPT_SACCTMGR_ADD_USER
	slurm_mutex_unlock(&assoc_lock);
#endif


	/* Since we are already removed all the items from assoc_list
	 * we need to work off the update_list from here on out.
	 */
	itr = list_iterator_create(kingbase_conn->update_list);;
	while ((update_object = list_next(itr))) {
		if (!update_object->objects ||
		    !list_count(update_object->objects))
			continue;
		if (update_object->type == SLURMDB_ADD_ASSOC)
			break;
	}
	list_iterator_destroy(itr);

	if (update_object && update_object->objects
	    && list_count(update_object->objects))
		assoc_list_tmp = update_object->objects;

	if (assoc_list_tmp) {
		ListIterator itr2 = list_iterator_create(assoc_list_tmp);

		if (!moved_parent) {
			char *cluster_name;

			itr = list_iterator_create(local_cluster_list);
			while ((cluster_name = list_next(itr))) {
				uint32_t smallest_lft = 0xFFFFFFFF;
				while ((object = list_next(itr2))) {
					if (object->lft < smallest_lft
					    && !xstrcmp(object->cluster,
							cluster_name))
						smallest_lft = object->lft;
				}
				list_iterator_reset(itr2);
				/* now get the lowest lft from the
				   added files by cluster */
				if (smallest_lft != 0xFFFFFFFF)
					rc = as_kingbase_get_modified_lfts(
						kingbase_conn, cluster_name,
						smallest_lft);
			}
			list_iterator_destroy(itr);
		}

		/* make sure we don't have any other default accounts */
		list_iterator_reset(itr2);
		while ((object = list_next(itr2))) {
			if ((object->is_def != 1) || !object->cluster
			    || !object->acct || !object->user)
				continue;

			if ((rc = _reset_default_assoc(
				     kingbase_conn, object,
				     &query, moved_parent ? 0 : 1))
			    != SLURM_SUCCESS) {
				xfree(query);
				goto end_it;
			}
		}
		list_iterator_destroy(itr2);
		/* This temp list is no longer needed */
#ifdef __METASTACK_OPT_SACCTMGR_ADD_USER
 		if (!acct_added)
 			assoc_list_tmp = NULL;
#else
		assoc_list_tmp = NULL;
#endif

	}

	if (query) {
		DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", query);
		//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);

		fetch_flag_t *fetch_flag = NULL;
		fetch_result_t *data_rt = NULL;
		fetch_flag = set_fetch_flag(false, false, false);
		data_rt = xmalloc(sizeof(fetch_result_t));
		rc = kingbase_for_fetch(kingbase_conn, query, fetch_flag, data_rt);
		free_res_data(data_rt, fetch_flag);	

		xfree(query);
		if (rc != SLURM_SUCCESS)
			error("Couldn't update defaults");
	}
end_it:

#ifdef __METASTACK_OPT_SACCTMGR_ADD_USER
 	/* If you add a child account and it's parent account 
	has a coordinator, update the coordinator of the parent account */
	if (assoc_list_tmp && acct_added && (rc == SLURM_SUCCESS)) {
		ListIterator itr3 = list_iterator_create(assoc_list_tmp);
		KCIResult *result1 = NULL;

		
		while ((object = list_next(itr3))){
			if(object->parent_acct){
				char *extra_parent = NULL;
				xstrfmtcat(extra_parent, "(acct='%s'" , object->parent_acct);

				char *parent_acct = xstrdup(object->parent_acct);

				while (parent_acct) {
					KCIResult *result2 = NULL;
					char *query2 = xstrdup_printf(
						"select parent_acct from `%s_%s` where acct='%s' and `user`='' and deleted=0;",
						object->cluster, assoc_table, parent_acct);
					DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", query2);
					xfree(parent_acct);
					if (!(result2 = kingbase_db_query_ret(
									kingbase_conn, query2, 0))) {
						xfree(query2);
						rc = SLURM_ERROR;
						break;
					}
					xfree(query2);

					if(KCIResultGetRowCount(result2) > 0){
						parent_acct = xstrdup(KCIResultGetColumnValue(result2, 0, 0));
						xstrfmtcat(extra_parent, "or acct='%s'", parent_acct);
					} else {
						parent_acct = NULL;
					}
					KCIResultDealloc(result2);
				}
				if (parent_acct) {
					xfree(parent_acct);
				}

				if (rc == SLURM_ERROR) {
					xfree(extra_parent);
					break;
				}

				xstrfmtcat(extra_parent, ")");
				
				char *query1 = xstrdup_printf(
					"select `user` from %s where %s and deleted=0",
					acct_coord_table, extra_parent);
				
				DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", query1);
				xfree(extra_parent);
				if (!(result1 = kingbase_db_query_ret(
							kingbase_conn, query1, 0))) {
					xfree(query1);
					rc = SLURM_ERROR;
					break;
				}
				xfree(query1);

				for(int i = 0; i < KCIResultGetRowCount(result1); i++){
					slurmdb_user_rec_t *coord_user = xmalloc(sizeof(slurmdb_user_rec_t));
					coord_user->coord_accts = list_create(slurmdb_destroy_coord_rec);

					coord_user->name = xstrdup(KCIResultGetColumnValue(result1, i, 0));
					_get_user_coords(kingbase_conn, coord_user);			
					
					if (addto_update_list(kingbase_conn->update_list, 
							SLURMDB_ADD_COORD, coord_user) != SLURM_SUCCESS) {
						error("addto_update_list fail");
						slurmdb_destroy_user_rec(coord_user);
					}
						
				}
				KCIResultDealloc(result1);
			}
		}
		list_iterator_destroy(itr3);
		assoc_list_tmp = NULL;
	}			
#endif

	if (rc == SLURM_SUCCESS) {
		_make_sure_users_have_default(kingbase_conn, added_user_list,
					      local_cluster_list);
		FREE_NULL_LIST(added_user_list);

		if (txn_query) {
			xstrcat(txn_query, ";");
			debug4("%d(%s:%d) query\n%s",
			       kingbase_conn->conn, THIS_FILE,
			       __LINE__, txn_query);
			//info("[query] line %d, %s: txn_query: %s", __LINE__, __func__, txn_query);	   
			fetch_flag_t *fetch_flag = NULL;
			fetch_result_t *data_rt = NULL;
			fetch_flag = set_fetch_flag(false, false, false);
			data_rt = xmalloc(sizeof(fetch_result_t));
			rc = kingbase_for_fetch(kingbase_conn, txn_query, fetch_flag, data_rt);
			free_res_data(data_rt, fetch_flag);	

			xfree(txn_query);
			if (rc != SLURM_SUCCESS) {
				error("Couldn't add txn");
				rc = SLURM_SUCCESS;
			}
		}
		if (moved_parent) {
			slurmdb_assoc_cond_t assoc_cond;
			/* now we need to send the update of the new parents and
			 * limits, so just to be safe, send the whole
			 * tree because we could have some limits that
			 * were affected but not noticed.
			 */
			/* we can probably just look at the mod time now but
			 * we will have to wait for the next revision number
			 * since you can't query on mod time here and I don't
			 * want to rewrite code to make it happen
			 */
			memset(&assoc_cond, 0, sizeof(assoc_cond));
			assoc_cond.cluster_list = local_cluster_list;
#ifdef __METASTACK_OPT_LIST_USER
			if (!(assoc_list_tmp =
			      as_kingbase_get_assocs(kingbase_conn, uid, &assoc_cond, false))) {
				FREE_NULL_LIST(local_cluster_list);
				return rc;
			}
#else
			if (!(assoc_list_tmp =
			      as_kingbase_get_assocs(kingbase_conn, uid, &assoc_cond))) {
				FREE_NULL_LIST(local_cluster_list);
				return rc;
			}
#endif

			_move_assoc_list_to_update_list(kingbase_conn->update_list,
							assoc_list_tmp);
			FREE_NULL_LIST(assoc_list_tmp);
		}

		/*
		 * We need to refresh the assoc_mgr_user_list to ensure that
		 * coordinators of parent accounts are also assigned to
		 * subaccounts potentially added here.
		 */

#ifdef __METASTACK_OPT_SACCTMGR_ADD_USER
  		/* We don't  need to refresh the assoc_mgr_user_list. */
			
#else
		if (acct_added) {
			if (assoc_mgr_refresh_lists((void *)kingbase_conn,
						    ASSOC_MGR_CACHE_USER)) {
				error ("Cannot refresh users/coordinators cache after new ccount was added");
				rc = SLURM_ERROR;
			}
		}
#endif

	} else {
		FREE_NULL_LIST(added_user_list);
		xfree(txn_query);
		reset_kingbase_conn(kingbase_conn);
	}
	FREE_NULL_LIST(local_cluster_list);
	return rc;
}

extern List as_kingbase_modify_assocs(kingbase_conn_t *kingbase_conn, uint32_t uid,
				   slurmdb_assoc_cond_t *assoc_cond,
				   slurmdb_assoc_rec_t *assoc)
{
	ListIterator itr = NULL;
	List ret_list = NULL;
	int rc = SLURM_SUCCESS;
	char *object = NULL;
	char *vals = NULL, *extra = NULL, *query = NULL;
	int i = 0;
	bool is_admin=0, same_user=0;
	KCIResult *result = NULL;
	slurmdb_user_rec_t user;
	char *tmp_char1=NULL, *tmp_char2=NULL;
	char *cluster_name = NULL;
	char *prefix = "t1";
	List use_cluster_list = NULL;
	bool locked = false;

	if (!assoc_cond || !assoc) {
		error("we need something to change");
		return NULL;
	}

	if (check_connection(kingbase_conn) != SLURM_SUCCESS)
		return NULL;

	memset(&user, 0, sizeof(slurmdb_user_rec_t));
	user.uid = uid;

	if (!(is_admin = is_user_min_admin_level(
		      kingbase_conn, uid, SLURMDB_ADMIN_OPERATOR))) {
		if (is_user_any_coord(kingbase_conn, &user)) {
			goto is_same_user;
		} else if (assoc_cond->user_list
			   && (list_count(assoc_cond->user_list) == 1)) {
			uid_t pw_uid;
			char *name;
			name = list_peek(assoc_cond->user_list);
		        if ((uid_from_string (name, &pw_uid) >= 0)
			    && (pw_uid == uid)) {
				uint16_t is_def = assoc->is_def;
				uint32_t def_qos_id = assoc->def_qos_id;
				/* Make sure they aren't trying to
				   change something they aren't
				   allowed to.  Currently they are
				   only allowed to change the default
				   account, and default QOS.
				*/
				slurmdb_init_assoc_rec(assoc, 1);

				assoc->is_def = is_def;
				assoc->def_qos_id = def_qos_id;
				same_user = 1;

				goto is_same_user;
			}
		}

		error("Only admins/coordinators can modify associations");
		errno = ESLURM_ACCESS_DENIED;
		return NULL;
	}
is_same_user:

	if ((assoc_cond->qos_list && list_count(assoc_cond->qos_list))
	    || assoc_cond->with_sub_accts)
		prefix = "t2";
#ifdef __METASTACK_OPT_LIST_USER
	(void) _setup_assoc_cond_limits(assoc_cond, prefix, &extra, false);
#else
	(void) _setup_assoc_cond_limits(assoc_cond, prefix, &extra);
#endif 

	/* This needs to be here to make sure we only modify the
	   correct set of assocs The first clause was already
	   taken care of above. */
	if (assoc_cond->user_list && !list_count(assoc_cond->user_list)) {
		debug4("no user specified looking at users");
		xstrcat(extra, " and `user` != '' ");
	} else if (!assoc_cond->user_list) {
		debug4("no user specified looking at accounts");
		xstrcat(extra, " and `user` = '' ");
	}

	if ((rc = setup_assoc_limits(assoc, &tmp_char1, &tmp_char2,
				     &vals, QOS_LEVEL_MODIFY, 0))) {
		xfree(tmp_char1);
		xfree(tmp_char2);
		xfree(vals);
		xfree(extra);
		errno = rc;
		error("%s: Failed, setup_assoc_limits functions returned error",
		      __func__);
		return NULL;
	}
	xfree(tmp_char1);
	xfree(tmp_char2);

	if (!extra || (!vals && !assoc->parent_acct)) {
		xfree(vals);
		xfree(extra);
		errno = SLURM_NO_CHANGE_IN_DATA;
		error("Nothing to change");
		return NULL;
	}

	xstrfmtcat(object, "t1.%s", massoc_req_inx[0]);
	for(i=1; i<MASSOC_COUNT; i++)
		xstrfmtcat(object, ", t1.%s", massoc_req_inx[i]);

	ret_list = list_create(xfree_ptr);

	if (assoc_cond->cluster_list && list_count(assoc_cond->cluster_list))
		use_cluster_list = assoc_cond->cluster_list;
	else {
		slurm_rwlock_rdlock(&as_kingbase_cluster_list_lock);
		use_cluster_list = list_shallow_copy(as_kingbase_cluster_list);
		locked = true;
	}

#ifdef __METASTACK_OPT_SACCTMGR_ADD_USER
	slurm_mutex_lock(&assoc_lock);
#endif

	itr = list_iterator_create(use_cluster_list);
	while ((cluster_name = list_next(itr))) {
		char *qos_extra = _setup_assoc_cond_qos(
			assoc_cond, cluster_name);

		xstrfmtcat(query, "select %s "
			   "from `%s_%s` as t1%s%s "
			   "order by lft FOR UPDATE;",
			   object, cluster_name,
			   assoc_table, qos_extra, extra);
		xfree(qos_extra);
		DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", query);
		//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);
		result = kingbase_db_query_ret(kingbase_conn, query, 0);
		if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK) {
			KCIResultDealloc(result);
			xfree(query);
			if (!strstr(KCIConnectionGetLastError(kingbase_conn->db_conn),"不存在")
				|| strstr(KCIConnectionGetLastError(kingbase_conn->db_conn),"not exist")) {
				FREE_NULL_LIST(ret_list);
				ret_list = NULL;
			}
			break;
		}
		xfree(query);
		rc = _process_modify_assoc_results(kingbase_conn, result, assoc,
						   &user, cluster_name, vals,
						   is_admin, same_user,
						   ret_list);
		KCIResultDealloc(result);

		if ((rc == ESLURM_INVALID_PARENT_ACCOUNT)
		    || (rc == ESLURM_SAME_PARENT_ACCOUNT)) {
			continue;
		} else if (rc != SLURM_SUCCESS) {
			FREE_NULL_LIST(ret_list);
			ret_list = NULL;
			break;
		}
	}

#ifdef __METASTACK_OPT_SACCTMGR_ADD_USER
	slurm_mutex_unlock(&assoc_lock);
#endif

	list_iterator_destroy(itr);
	if (locked) {
		FREE_NULL_LIST(use_cluster_list);
		slurm_rwlock_unlock(&as_kingbase_cluster_list_lock);
	}
	xfree(vals);
	xfree(object);
	xfree(extra);

	if (!ret_list) {
		reset_kingbase_conn(kingbase_conn);
		errno = rc;
		return NULL;
	} else if (!list_count(ret_list)) {
		reset_kingbase_conn(kingbase_conn);
		errno = SLURM_NO_CHANGE_IN_DATA;
		DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "didn't affect anything");
		//info("[query] line %d, didn't affect anything", __LINE__);
		return ret_list;
	}

	return ret_list;
}

extern List as_kingbase_remove_assocs(kingbase_conn_t *kingbase_conn, uint32_t uid,
				   slurmdb_assoc_cond_t *assoc_cond)
{
	ListIterator itr = NULL;
	List ret_list = NULL;
	int rc = SLURM_SUCCESS;
	char *object = NULL, *cluster_name = NULL;
	char *extra = NULL, *query = NULL, *name_char = NULL;
	int i = 0, is_admin = 0;
	KCIResult *result = NULL;

	slurmdb_user_rec_t user;
	char *prefix = "t1";
	List use_cluster_list = NULL;
	bool jobs_running = 0, default_account = false, locked = false;

	if (!assoc_cond) {
		error("we need something to change");
		return NULL;
	}

	if (check_connection(kingbase_conn) != SLURM_SUCCESS)
		return NULL;

	memset(&user, 0, sizeof(slurmdb_user_rec_t));
	user.uid = uid;

	if (!(is_admin = is_user_min_admin_level(
		      kingbase_conn, uid, SLURMDB_ADMIN_OPERATOR))) {
		if (!is_user_any_coord(kingbase_conn, &user)) {
			error("Only admins/coordinators can "
			      "remove associations");
			errno = ESLURM_ACCESS_DENIED;
			return NULL;
		}
	}

	if ((assoc_cond->qos_list && list_count(assoc_cond->qos_list))
	    || assoc_cond->with_sub_accts)
		prefix = "t2";
#ifdef __METASTACK_OPT_LIST_USER
	(void)_setup_assoc_cond_limits(assoc_cond, prefix, &extra, false);
#else
	(void)_setup_assoc_cond_limits(assoc_cond, prefix, &extra);
#endif

	xstrcat(object, rassoc_req_inx[0]);
	for(i=1; i<RASSOC_COUNT; i++)
		xstrfmtcat(object, ", %s", rassoc_req_inx[i]);

	ret_list = list_create(xfree_ptr);

	if (assoc_cond->cluster_list && list_count(assoc_cond->cluster_list))
		use_cluster_list = assoc_cond->cluster_list;
	else {
		slurm_rwlock_rdlock(&as_kingbase_cluster_list_lock);
		use_cluster_list = list_shallow_copy(as_kingbase_cluster_list);
		locked = true;
	}

#ifdef __METASTACK_OPT_SACCTMGR_ADD_USER
	slurm_mutex_lock(&assoc_lock);
#endif

	itr = list_iterator_create(use_cluster_list);
	while ((cluster_name = list_next(itr))) {
		char *qos_extra = _setup_assoc_cond_qos(
			assoc_cond, cluster_name);

		query = xstrdup_printf("select t1.lft, t1.rgt from "
				       "`%s_%s` as t1%s%s order by "
				       "lft FOR UPDATE;",
				       cluster_name, assoc_table,
				       qos_extra, extra);
		xfree(qos_extra);
		DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", query);
		//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);
		result = kingbase_db_query_ret(kingbase_conn, query, 0);
		if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK) {
			KCIResultDealloc(result);
			xfree(query);
			if (!strstr(KCIConnectionGetLastError(kingbase_conn->db_conn),"不存在")
				|| strstr(KCIConnectionGetLastError(kingbase_conn->db_conn),"not exist")) {
				FREE_NULL_LIST(ret_list);
				ret_list = NULL;
			}
			break;
		}
		xfree(query);

		if (!KCIResultGetRowCount(result)) {
			KCIResultDealloc(result);
			continue;
		}
		for(int i = 0; i < KCIResultGetRowCount(result); i++){
			if (name_char)
				xstrfmtcat(name_char,
					   " or lft between %s and %s",
					   KCIResultGetColumnValue(result, i, 0), KCIResultGetColumnValue(result, i, 1));
			else
				xstrfmtcat(name_char, "lft between %s and %s",
					   KCIResultGetColumnValue(result, i, 0), KCIResultGetColumnValue(result, i, 1));
		}
		KCIResultDealloc(result);

		query = xstrdup_printf("select distinct %s "
				       "from `%s_%s` where (%s) "
				       "and deleted = 0 order by lft;",
				       object,
				       cluster_name, assoc_table, name_char);
		DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", query);
		//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);
		result = kingbase_db_query_ret(kingbase_conn, query, 0);
		if (KCIResultGetStatusCode(result) != EXECUTE_TUPLES_OK) {
			KCIResultDealloc(result);
			xfree(query);
			xfree(name_char);
			FREE_NULL_LIST(ret_list);
			ret_list = NULL;
			break;
		}
		xfree(query);

		rc = _process_remove_assoc_results(kingbase_conn, result,
						   &user, cluster_name,
						   name_char, is_admin,
						   ret_list, &jobs_running,
						   &default_account);
		xfree(name_char);
		KCIResultDealloc(result);

		if (rc != SLURM_SUCCESS) {
			FREE_NULL_LIST(ret_list);
			ret_list = NULL;
			break;
		}
	}

#ifdef __METASTACK_OPT_SACCTMGR_ADD_USER
	slurm_mutex_unlock(&assoc_lock);
#endif

	list_iterator_destroy(itr);
	if (locked) {
		FREE_NULL_LIST(use_cluster_list);
		slurm_rwlock_unlock(&as_kingbase_cluster_list_lock);
	}

	xfree(object);
	xfree(extra);

	if (!ret_list) {
		reset_kingbase_conn(kingbase_conn);
		return NULL;
	} else if (!list_count(ret_list)) {
		reset_kingbase_conn(kingbase_conn);
		errno = SLURM_NO_CHANGE_IN_DATA;
		DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "didn't affect anything");
		//info("[query] line %d, didn't affect anything", __LINE__);
		return ret_list;
	}
	if (default_account)
		errno = ESLURM_NO_REMOVE_DEFAULT_ACCOUNT;
	else if (jobs_running)
		errno = ESLURM_JOBS_RUNNING_ON_ASSOC;
	else
		errno = SLURM_SUCCESS;
	return ret_list;
}

#ifdef __METASTACK_OPT_LIST_USER
extern List as_kingbase_get_assocs(kingbase_conn_t *kingbase_conn, uid_t uid,
				slurmdb_assoc_cond_t *assoc_cond, bool list_all)
#else
extern List as_kingbase_get_assocs(kingbase_conn_t *kingbase_conn, uid_t uid,
				slurmdb_assoc_cond_t *assoc_cond)
#endif
{
	//DEF_TIMERS;
	char *extra = NULL;
	char *tmp = NULL;
	List assoc_list = NULL;
	ListIterator itr = NULL;
	int i=0, is_admin=1;
	slurmdb_user_rec_t user;
	char *prefix = "t1";
	List use_cluster_list = NULL;
	char *cluster_name = NULL;
	bool locked = false;

	if (!assoc_cond) {
		xstrcat(extra, " where deleted=0");
		goto empty;
	}

	if (check_connection(kingbase_conn) != SLURM_SUCCESS)
		return NULL;

	memset(&user, 0, sizeof(slurmdb_user_rec_t));
	user.uid = uid;

	if (slurm_conf.private_data & PRIVATE_DATA_USERS) {
		if (!(is_admin = is_user_min_admin_level(
			      kingbase_conn, uid, SLURMDB_ADMIN_OPERATOR))) {
			/* Fill in the user with any accounts they may
			   be coordinator of, which is checked inside
			   _cluster_get_assocs.
			*/
			assoc_mgr_fill_in_user(
				kingbase_conn, &user, 1, NULL, false);
		}
		if (!is_admin && !user.name) {
			debug("User %u has no associations, and is not admin, "
			      "so not returning any.", user.uid);
			return NULL;
		}
	}

	if ((assoc_cond->qos_list && list_count(assoc_cond->qos_list))
	    || assoc_cond->with_sub_accts)
		prefix = "t2";
#ifdef __METASTACK_OPT_LIST_USER
	(void) _setup_assoc_cond_limits(assoc_cond, prefix, &extra, list_all);
#else
	(void) _setup_assoc_cond_limits(assoc_cond, prefix, &extra);
#endif

empty:
	xfree(tmp);
	xstrfmtcat(tmp, "t1.%s", assoc_req_inx[i]);
	for(i=1; i<ASSOC_REQ_COUNT; i++) {
		xstrfmtcat(tmp, ", t1.%s", assoc_req_inx[i]);
	}
	assoc_list = list_create(slurmdb_destroy_assoc_rec);

	if (assoc_cond && assoc_cond->cluster_list &&
	    list_count(assoc_cond->cluster_list)) {
		use_cluster_list = assoc_cond->cluster_list;
	} else {
		slurm_rwlock_rdlock(&as_kingbase_cluster_list_lock);
		use_cluster_list = list_shallow_copy(as_kingbase_cluster_list);
		locked = true;
	}
	itr = list_iterator_create(use_cluster_list);
	while ((cluster_name = list_next(itr))) {
		int rc;
		if ((rc = _cluster_get_assocs(kingbase_conn, &user, assoc_cond,
					      cluster_name, tmp, extra,
					      is_admin, assoc_list))
		    != SLURM_SUCCESS) {
			FREE_NULL_LIST(assoc_list);
			assoc_list = NULL;
			break;
		}
	}
	list_iterator_destroy(itr);
	if (locked) {
		FREE_NULL_LIST(use_cluster_list);
		slurm_rwlock_unlock(&as_kingbase_cluster_list_lock);
	}
	xfree(tmp);
	xfree(extra);

	//END_TIMER2("get_assocs");
	return assoc_list;
}

extern int as_kingbase_reset_lft_rgt(kingbase_conn_t *kingbase_conn, uid_t uid,
				  List cluster_list)
{
	List assoc_list = NULL;
	ListIterator itr = NULL, assoc_itr;
	int i=0, is_admin=1;
	slurmdb_user_rec_t user;
	char *query = NULL, *tmp = NULL, *cluster_name = NULL;
	slurmdb_assoc_cond_t assoc_cond;
	slurmdb_assoc_rec_t *assoc_rec;
	int rc = SLURM_SUCCESS;
	slurmdb_update_object_t *update_object;
	slurmdb_update_type_t type;
	List use_cluster_list = as_kingbase_cluster_list;

	info("Resetting lft and rgt's called");
	/* This is not safe if ran during the middle of a slurmdbd
	 * run since we can not lock as_kingbase_cluster_list_lock when
	 * no list is given.  At the time of this writing the function
	 * was only called at the beginning of the DBD.  If this ever
	 * changes please make the appropriate changes to allow empty lists.
	 */
	if (cluster_list && list_count(cluster_list))
		use_cluster_list = cluster_list;
	/* else */
	/* 	slurm_mutex_lock(&as_kingbase_cluster_list_lock); */

	memset(&assoc_cond, 0, sizeof(slurmdb_assoc_cond_t));

	xfree(tmp);
	xstrfmtcat(tmp, "t1.%s", assoc_req_inx[i]);
	for (i=1; i<ASSOC_REQ_COUNT; i++) {
		xstrfmtcat(tmp, ", t1.%s", assoc_req_inx[i]);
	}

	memset(&user, 0, sizeof(slurmdb_user_rec_t));
	user.uid = uid;

	itr = list_iterator_create(use_cluster_list);
	while ((cluster_name = list_next(itr))) {
		time_t now = time(NULL);
		DEF_TIMERS;
		START_TIMER;
		info("Resetting cluster %s", cluster_name);
		assoc_list = list_create(slurmdb_destroy_assoc_rec);
		/* set this up to get the associations without parent_limits */
		assoc_cond.without_parent_limits = 1;

		/* Get the associations for the cluster that needs to
		 * somehow got lft and rgt's messed up. */
		if ((rc = _cluster_get_assocs(kingbase_conn, &user, &assoc_cond,
					      cluster_name, tmp,
					      " deleted=1 or deleted=0",
					      is_admin, assoc_list))
		    != SLURM_SUCCESS) {
			info("fail for cluster %s", cluster_name);
			FREE_NULL_LIST(assoc_list);
			continue;
		}

		if (!list_count(assoc_list)) {
			info("Cluster %s has no associations, nothing to reset",
			     cluster_name);
			FREE_NULL_LIST(assoc_list);
			continue;
		}

		slurmdb_sort_hierarchical_assoc_list(assoc_list, false);
		info("Got current associations for cluster %s", cluster_name);
		/* Set the cluster name to the tmp name and remove qos */
		assoc_itr = list_iterator_create(assoc_list);
		while ((assoc_rec = list_next(assoc_itr))) {
			if (assoc_rec->id == 1) {
				/* Remove root association as we will make it
				 * manually in the next step.
				 */
				list_delete_item(assoc_itr);
				continue;
			}
			xfree(assoc_rec->cluster);
			assoc_rec->cluster = xstrdup(tmp_cluster_name);
			/* Remove the qos_list just to simplify things
			 * since we really want to just simplify
			 * things.
			 */
			FREE_NULL_LIST(assoc_rec->qos_list);
		}
		list_iterator_destroy(assoc_itr);

		/* What we are going to do now is add all the
		 * associations to a tmp cluster this will recreate
		 * the lft and rgt hierarchy.  Then when this is done
		 * we will move those lft/rgts back over to the
		 * original cluster based on the same id_assoc's.
		 * After that we will send these new objects out to
		 * the slurmctld to use.
		 */

		create_cluster_assoc_table(kingbase_conn, tmp_cluster_name);

		/* We must add the root association here to make it so
		 * the adds work afterwards.
		 */
		xstrfmtcat(query,
			   "insert into `%s_%s` "
			   "(creation_time, mod_time, acct, lft, rgt) "
			   "values (%ld, %ld, 'root', 1, 2) "
			   "on duplicate key update deleted=0, "
			   //"id_assoc=nextval(id_assoc), mod_time=%ld;",
			   "mod_time=%ld;",
			   tmp_cluster_name, assoc_table, now, now, now);

		DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", query);
		//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);

		fetch_flag_t *fetch_flag = NULL;
		fetch_result_t *data_rt = NULL;
		fetch_flag = set_fetch_flag(false, false, false);
		data_rt = xmalloc(sizeof(fetch_result_t));
		rc = kingbase_for_fetch(kingbase_conn, query, fetch_flag, data_rt);
		free_res_data(data_rt, fetch_flag);	
		xfree(query);

		if (rc != SLURM_SUCCESS) {
			error("Couldn't add cluster root assoc");
			break;
		} 

		info("Redoing the hierarchy in a temporary table");
		if (as_kingbase_add_assocs(kingbase_conn, uid, assoc_list) !=
		    SLURM_SUCCESS)
			goto endit;

		/* Since the list we now have has deleted
		 * items in it we need to get a list with just
		 * the current items instead
		 */
		list_flush(assoc_list);

		info("Resetting cluster with correct lft and rgt's");
		/* Update the normal table with the correct lft and rgts */
		query = xstrdup_printf(
			"update `%s_%s` t1 left outer join `%s_%s` t2 on "
			"t1.id_assoc = t2.id_assoc set t1.lft = t2.lft, "
			"t1.rgt = t2.rgt, t1.mod_time = t2.mod_time;",
			cluster_name, assoc_table,
			tmp_cluster_name, assoc_table);

		DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", query);
		//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);

		fetch_flag = set_fetch_flag(false, false, false);
		data_rt = xmalloc(sizeof(fetch_result_t));
		rc = kingbase_for_fetch(kingbase_conn, query, fetch_flag, data_rt);
		free_res_data(data_rt, fetch_flag);	
		xfree(query);
		if (rc != SLURM_SUCCESS)
			error("Couldn't fix assocs");

		/* Now we will remove the adds that happened and
		 * replace them with mod's so we can push the new
		 * lft's to the cluster.
		 */
		type = SLURMDB_ADD_ASSOC;
		assoc_itr = list_iterator_create(kingbase_conn->update_list);
		while ((update_object = list_next(assoc_itr))) {
			if (update_object->type == type) {
				list_delete_item(assoc_itr);
				break;
			}
		}
		list_iterator_destroy(assoc_itr);

		/* Make the mod assoc update_object if it doesn't exist */
		type = SLURMDB_MODIFY_ASSOC;
		if (!(update_object = list_find_first(
			      kingbase_conn->update_list,
			      slurmdb_find_update_object_in_list,
			      &type))) {
			update_object = xmalloc(
				sizeof(slurmdb_update_object_t));
			list_append(kingbase_conn->update_list, update_object);
			update_object->type = type;
			update_object->objects = list_create(
				slurmdb_destroy_assoc_rec);
		}

		/* set this up to get the associations with parent_limits */
		assoc_cond.without_parent_limits = 0;
		if ((rc = _cluster_get_assocs(kingbase_conn, &user, &assoc_cond,
					      cluster_name, tmp,
					      " deleted=0",
					      is_admin, assoc_list))
		    != SLURM_SUCCESS) {
			goto endit;
		}
		list_transfer(update_object->objects, assoc_list);
	endit:
		FREE_NULL_LIST(assoc_list);
		/* Get rid of the temporary table. */
		query = xstrdup_printf("drop table `%s_%s`;",
				       tmp_cluster_name, assoc_table);
		//info("[query] line %d, %s: query: %s", __LINE__, __func__, query);			   

		fetch_flag = set_fetch_flag(false, false, false);
		data_rt = xmalloc(sizeof(fetch_result_t));
		rc = kingbase_for_fetch(kingbase_conn, query, fetch_flag, data_rt);
		free_res_data(data_rt, fetch_flag);	

		xfree(query);
		if (rc != SLURM_SUCCESS) {
			error("problem with update query");
			rc = SLURM_ERROR;
		}
		END_TIMER;
		info("resetting took %s", TIME_STR);
	}
	list_iterator_destroy(itr);

	xfree(tmp);

	/* if (use_cluster_list == as_kingbase_cluster_list) */
	/* 	slurm_mutex_unlock(&as_kingbase_cluster_list_lock); */

	return rc;
}

extern int as_kingbase_assoc_remove_default(kingbase_conn_t *kingbase_conn,
					 List user_list, List cluster_list)
{
	char *query = NULL;
	List use_cluster_list = NULL;
	ListIterator itr, itr2;
	slurmdb_assoc_rec_t assoc;
	bool locked = false;
	int rc = SLURM_SUCCESS;

	xassert(user_list);

	if (!(slurmdbd_conf->flags & DBD_CONF_FLAG_ALLOW_NO_DEF_ACCT))
		return ESLURM_NO_REMOVE_DEFAULT_ACCOUNT;

	slurmdb_init_assoc_rec(&assoc, 0);
	assoc.acct = "";
	assoc.is_def = 1;

	if (cluster_list && list_count(cluster_list))
		use_cluster_list = cluster_list;
	else {
		slurm_rwlock_rdlock(&as_kingbase_cluster_list_lock);
		use_cluster_list = list_shallow_copy(as_kingbase_cluster_list);
		locked = true;
	}

	itr = list_iterator_create(use_cluster_list);
	itr2 = list_iterator_create(user_list);
	while ((assoc.cluster = list_next(itr))) {
		list_iterator_reset(itr2);
		while ((assoc.user = list_next(itr2))) {
			rc = _reset_default_assoc(
				kingbase_conn, &assoc, &query, true);

			if (rc != SLURM_SUCCESS)
				break;
		}
		if (rc != SLURM_SUCCESS)
			break;
	}
	list_iterator_destroy(itr2);
	list_iterator_destroy(itr);

	if (locked) {
		FREE_NULL_LIST(use_cluster_list);
		slurm_rwlock_unlock(&as_kingbase_cluster_list_lock);
	}

	if (rc != SLURM_SUCCESS)
		xfree(query);

	if (query) {
		DB_DEBUG(DB_ASSOC, kingbase_conn->conn, "query\n%s", query);
		rc = kingbase_db_query(kingbase_conn, query);
		xfree(query);
		if (rc != SLURM_SUCCESS)
			error("Couldn't remove default assocs");
	}

	return rc;
}
